mirror of https://github.com/OpenVidu/openvidu.git
ov-components: Revamp participant panel item for improved UI/UX and accessibility; add mute/unmute functionality and translations
parent
4bf351b2df
commit
00fcb0b115
|
@ -1,33 +1,76 @@
|
|||
<mat-list>
|
||||
<mat-list-item>
|
||||
<div matListItemIcon class="participant-avatar" [style.background-color]="_participant.colorProfile">
|
||||
<!-- Main participant container with improved structure -->
|
||||
<div class="participant-container" [attr.data-participant-id]="_participant?.sid">
|
||||
<!-- Avatar section with dynamic color -->
|
||||
<div
|
||||
class="participant-avatar"
|
||||
[style.background-color]="_participant?.colorProfile"
|
||||
[attr.aria-label]="'Avatar for ' + participantDisplayName"
|
||||
>
|
||||
<mat-icon>person</mat-icon>
|
||||
</div>
|
||||
<h3 matListItemTitle class="participant-name">{{ _participant.name }}
|
||||
<span *ngIf="_participant.isLocal"> ({{ 'PANEL.PARTICIPANTS.YOU' | translate }})</span>
|
||||
</h3>
|
||||
<p matListItemLine class="participant-subtitle">{{ _participant | tracksPublishedTypes }}</p>
|
||||
<!-- <p matListItemLine>
|
||||
<span class="participant-subtitle"></span>
|
||||
</p> -->
|
||||
|
||||
<div class="participant-action-buttons" matListItemMeta>
|
||||
<!-- Content section with name and status -->
|
||||
<div class="participant-content">
|
||||
<div class="participant-name">
|
||||
{{ participantDisplayName }}
|
||||
<span *ngIf="isLocalParticipant" class="local-indicator">
|
||||
{{ 'PANEL.PARTICIPANTS.YOU' | translate }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="participant-subtitle">
|
||||
<span class="status-indicator">
|
||||
{{ _participant | tracksPublishedTypes }}
|
||||
</span>
|
||||
<!-- Additional status indicators -->
|
||||
<span *ngIf="_participant?.isMutedForcibly" class="status-indicator">
|
||||
<mat-icon>volume_off</mat-icon>
|
||||
{{ 'PANEL.PARTICIPANTS.MUTED' | translate }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action buttons section -->
|
||||
<div class="participant-action-buttons">
|
||||
<!-- Mute/Unmute button for remote participants -->
|
||||
<button
|
||||
mat-icon-button
|
||||
id="mute-btn"
|
||||
*ngIf="!_participant.isLocal && showMuteButton"
|
||||
[class.warn-btn]="_participant.isMutedForcibly"
|
||||
*ngIf="!isLocalParticipant && showMuteButton"
|
||||
[class.warn-btn]="_participant?.isMutedForcibly"
|
||||
(click)="toggleMuteForcibly()"
|
||||
[disabled]="!_participant"
|
||||
[disableRipple]="true"
|
||||
[attr.aria-label]="
|
||||
_participant?.isMutedForcibly
|
||||
? ('PANEL.PARTICIPANTS.UNMUTE' | translate) + ' ' + participantDisplayName
|
||||
: ('PANEL.PARTICIPANTS.MUTE' | translate) + ' ' + participantDisplayName
|
||||
"
|
||||
[matTooltip]="
|
||||
_participant?.isMutedForcibly ? ('PANEL.PARTICIPANTS.UNMUTE' | translate) : ('PANEL.PARTICIPANTS.MUTE' | translate)
|
||||
"
|
||||
>
|
||||
<mat-icon *ngIf="!_participant.isMutedForcibly">volume_up</mat-icon>
|
||||
<mat-icon *ngIf="_participant.isMutedForcibly">volume_off</mat-icon>
|
||||
<mat-icon *ngIf="!_participant?.isMutedForcibly">volume_up</mat-icon>
|
||||
<mat-icon *ngIf="_participant?.isMutedForcibly">volume_off</mat-icon>
|
||||
</button>
|
||||
|
||||
<!-- External item elements -->
|
||||
<ng-container *ngIf="participantPanelItemElementsTemplate">
|
||||
<!-- External item elements with improved structure -->
|
||||
<div class="external-elements" *ngIf="hasExternalElements">
|
||||
<ng-container *ngTemplateOutlet="participantPanelItemElementsTemplate"></ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content after local participant (only for local participant) -->
|
||||
<!-- <div
|
||||
class="after-local-content"
|
||||
*ngIf="hasAfterLocalContent"
|
||||
role="region"
|
||||
[attr.aria-label]="'Additional content for local participant'"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="afterLocalParticipantTemplate"></ng-container>
|
||||
</div> -->
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
|
|
|
@ -1,68 +1,419 @@
|
|||
:host {
|
||||
// Container for the participant item
|
||||
.participant-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-radius: var(--ov-surface-radius, 8px);
|
||||
background-color: var(--ov-surface-background, #ffffff);
|
||||
border-bottom: 1px solid var(--ov-surface-border, #e0e0e0);
|
||||
transition: all 0.2s ease-in-out;
|
||||
min-height: 64px;
|
||||
|
||||
// &:hover {
|
||||
// background-color: var(--ov-surface-hover, #f5f5f5);
|
||||
// transform: translateY(-1px);
|
||||
// box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
// }
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
// Loading state
|
||||
&.loading {
|
||||
opacity: 0.7;
|
||||
pointer-events: none;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid var(--ov-primary-color, #1976d2);
|
||||
border-radius: 50%;
|
||||
border-top-color: transparent;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
// Focus state for keyboard navigation
|
||||
&:focus-within {
|
||||
outline: 2px solid var(--ov-primary-color, #1976d2);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
// Avatar styling with improved design
|
||||
.participant-avatar {
|
||||
display: inherit;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: var(--ov-surface-radius);
|
||||
margin: auto !important;
|
||||
padding: 10px;
|
||||
color: #000000;
|
||||
margin-right: 12px;
|
||||
padding: 0;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
mat-icon {
|
||||
font-size: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.participant-subtitle {
|
||||
font-style: italic;
|
||||
font-size: 11px !important;
|
||||
margin: 0;
|
||||
color: var(--ov-text-surface-color);
|
||||
// Main content area
|
||||
.participant-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0; // Allows text truncation
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
// Participant name styling
|
||||
.participant-name {
|
||||
font-weight: bold !important;
|
||||
color: var(--ov-text-surface-color);
|
||||
font-weight: 600 !important;
|
||||
font-size: 14px;
|
||||
line-height: 1.2;
|
||||
color: var(--ov-text-primary, #212121);
|
||||
margin: 0 0 4px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
// Local participant indicator
|
||||
.local-indicator {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--ov-primary-color, #1976d2);
|
||||
background-color: var(--ov-primary-light, #e3f2fd);
|
||||
padding: 4px 8px;
|
||||
border-radius: var(--ov-surface-radius);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid var(--ov-primary-color, #1976d2);
|
||||
}
|
||||
}
|
||||
|
||||
// Subtitle styling
|
||||
.participant-subtitle {
|
||||
font-style: normal;
|
||||
font-size: 12px !important;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
color: var(--ov-text-secondary, #757575);
|
||||
line-height: 1.3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
// Status indicators
|
||||
.status-indicator {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
|
||||
mat-icon {
|
||||
font-size: 12px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
// Different colors for different statuses
|
||||
&.camera-on {
|
||||
color: var(--ov-success-color, #4caf50);
|
||||
}
|
||||
|
||||
&.camera-off {
|
||||
color: var(--ov-warning-color, #ff9800);
|
||||
}
|
||||
|
||||
&.microphone-muted {
|
||||
color: var(--ov-error-color, #d32f2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Action buttons container
|
||||
.participant-action-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
::ng-deep .participant-action-buttons > *:not(#mute-btn) {
|
||||
display: contents;
|
||||
// Mute button styling
|
||||
#mute-btn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
color: var(--ov-text-secondary, #757575);
|
||||
background-color: transparent;
|
||||
transition: all 0.2s ease-in-out;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--ov-surface-hover, #f5f5f5);
|
||||
color: var(--ov-text-primary, #212121);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
::ng-deep .participant-action-buttons > *:not(#mute-btn) > * {
|
||||
margin: auto;
|
||||
&:focus {
|
||||
outline: 2px solid var(--ov-primary-color, #1976d2);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&.warn-btn {
|
||||
color: var(--ov-error-color, #d32f2f);
|
||||
background-color: var(--ov-error-light, #ffebee);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--ov-error-color, #d32f2f);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
// Pulsing animation for muted state
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
font-size: 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
// After local participant content area
|
||||
.after-local-content {
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid var(--ov-surface-border, #e0e0e0);
|
||||
animation: fadeIn 0.3s ease-in-out;
|
||||
background-color: var(--ov-surface-alt, #fafafa);
|
||||
border-radius: var(--ov-surface-radius, 8px);
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
// External item elements styling
|
||||
.external-elements {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
// Custom styling for external buttons
|
||||
::ng-deep button {
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Material Design overrides for better integration
|
||||
mat-list {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-list-item {
|
||||
height: max-content !important;
|
||||
padding-bottom: 10px !important;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-list-item:hover {
|
||||
color: #000000 !important;
|
||||
}
|
||||
::ng-deep .mat-mdc-list-item:hover .mat-mdc-list-item-title {
|
||||
color: var(--ov-text-surface-color) !important;
|
||||
}
|
||||
|
||||
mat-list {
|
||||
padding: 3px;
|
||||
height: auto !important;
|
||||
padding: 0 !important;
|
||||
min-height: auto !important;
|
||||
border-radius: var(--ov-surface-radius, 8px);
|
||||
}
|
||||
|
||||
::ng-deep .mdc-list-item__content {
|
||||
padding-left: 10px !important;
|
||||
align-self: center !important;
|
||||
padding: 0 !important;
|
||||
align-self: stretch !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-list-base {
|
||||
--mdc-list-list-item-hover-label-text-color: unset;
|
||||
--mdc-list-list-item-hover-leading-icon-color: unset;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::ng-deep .mat-mdc-list-item:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
// Animations
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive design
|
||||
@media (max-width: 768px) {
|
||||
.participant-container {
|
||||
padding: 10px 12px;
|
||||
min-height: 56px;
|
||||
}
|
||||
|
||||
.participant-avatar {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-right: 10px;
|
||||
|
||||
mat-icon {
|
||||
font-size: 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
bottom: 1px;
|
||||
right: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.participant-name {
|
||||
font-size: 13px;
|
||||
|
||||
.local-indicator {
|
||||
font-size: 9px;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.participant-subtitle {
|
||||
font-size: 11px !important;
|
||||
}
|
||||
|
||||
#mute-btn {
|
||||
border-radius: 50%;
|
||||
color: var(--ov-text-surface-color);
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
|
||||
mat-icon {
|
||||
font-size: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.warn-btn {
|
||||
/* background-color: var(--ov-error-color) !important; */
|
||||
color: var(--ov-error-color);
|
||||
.after-local-content {
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
// High contrast mode support
|
||||
@media (prefers-contrast: high) {
|
||||
.participant-container {
|
||||
border: 2px solid var(--ov-text-primary, #212121);
|
||||
}
|
||||
|
||||
.participant-avatar {
|
||||
border: 2px solid var(--ov-surface-background, #ffffff);
|
||||
}
|
||||
|
||||
.local-indicator {
|
||||
border-width: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
// Reduced motion support
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.participant-container,
|
||||
.participant-avatar,
|
||||
#mute-btn,
|
||||
.after-local-content,
|
||||
.external-elements ::ng-deep button {
|
||||
transition: none;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.participant-container:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.participant-avatar:hover,
|
||||
#mute-btn:hover,
|
||||
.external-elements ::ng-deep button:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
#mute-btn.warn-btn {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Dark theme support
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.participant-container {
|
||||
background-color: var(--ov-surface-background, #424242);
|
||||
border-bottom-color: var(--ov-surface-border, #616161);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--ov-surface-hover, #484848);
|
||||
}
|
||||
}
|
||||
|
||||
.participant-name {
|
||||
color: var(--ov-text-primary, #ffffff);
|
||||
}
|
||||
|
||||
.participant-subtitle {
|
||||
color: var(--ov-text-secondary, #cccccc);
|
||||
}
|
||||
|
||||
.after-local-content {
|
||||
background-color: var(--ov-surface-alt, #373737);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { ParticipantPanelItemElementsDirective } from '../../../../directives/template/openvidu-components-angular.directive';
|
||||
// import { ParticipantPanelAfterLocalParticipantDirective } from '../../../../directives/template/internals.directive';
|
||||
import { ParticipantModel } from '../../../../models/participant.model';
|
||||
import { OpenViduComponentsConfigService } from '../../../../services/config/directive-config.service';
|
||||
import { ParticipantService } from '../../../../services/participant/participant.service';
|
||||
import { TemplateManagerService, ParticipantPanelItemTemplateConfiguration } from '../../../../services/template/template-manager.service';
|
||||
|
||||
/**
|
||||
*
|
||||
* The **ParticipantPanelItemComponent** is hosted inside of the {@link ParticipantsPanelComponent}.
|
||||
* It is in charge of displaying the participants information inside of the ParticipansPanelComponent.
|
||||
* It displays participant information with enhanced UI/UX, including support for custom content
|
||||
* injection through structural directives.
|
||||
*/
|
||||
|
||||
@Component({
|
||||
selector: 'ov-participant-panel-item',
|
||||
templateUrl: './participant-panel-item.component.html',
|
||||
|
@ -42,6 +42,17 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @ignore
|
||||
// */
|
||||
// @ContentChild(ParticipantPanelAfterLocalParticipantDirective)
|
||||
// set externalAfterLocalParticipant(afterLocalParticipant: ParticipantPanelAfterLocalParticipantDirective) {
|
||||
// this._externalAfterLocalParticipant = afterLocalParticipant;
|
||||
// if (afterLocalParticipant) {
|
||||
// this.updateTemplatesAndMarkForCheck();
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Template configuration managed by the service
|
||||
|
@ -50,21 +61,29 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
|
|||
|
||||
// Store directive references for template setup
|
||||
private _externalItemElements?: ParticipantPanelItemElementsDirective;
|
||||
// private _externalAfterLocalParticipant?: ParticipantPanelAfterLocalParticipantDirective;
|
||||
|
||||
/**
|
||||
* The participant to be displayed
|
||||
* @ignore
|
||||
*/
|
||||
@Input()
|
||||
set participant(participant: ParticipantModel) {
|
||||
this._participant = participant;
|
||||
this.cd.markForCheck();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @internal
|
||||
* Current participant being displayed
|
||||
*/
|
||||
_participant: ParticipantModel;
|
||||
|
||||
/**
|
||||
* Whether to show the mute button for remote participants
|
||||
*/
|
||||
@Input()
|
||||
muteButton: boolean = true;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
@ -91,14 +110,49 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* Toggles the mute state of a remote participant
|
||||
*/
|
||||
toggleMuteForcibly() {
|
||||
if (this._participant) {
|
||||
if (this._participant && !this._participant.isLocal) {
|
||||
this.participantService.setRemoteMutedForcibly(this._participant.sid, !this._participant.isMutedForcibly);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the template for content after local participant
|
||||
*/
|
||||
// get afterLocalParticipantTemplate(): TemplateRef<any> | undefined {
|
||||
// return this._externalAfterLocalParticipant?.template;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Checks if the current participant is the local participant
|
||||
*/
|
||||
get isLocalParticipant(): boolean {
|
||||
return this._participant?.isLocal || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the participant's display name
|
||||
*/
|
||||
get participantDisplayName(): string {
|
||||
return this._participant?.name || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if external elements are available
|
||||
*/
|
||||
get hasExternalElements(): boolean {
|
||||
return !!this.participantPanelItemElementsTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if after local participant content is available
|
||||
*/
|
||||
// get hasAfterLocalContent(): boolean {
|
||||
// return this.isLocalParticipant && !!this.afterLocalParticipantTemplate;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Sets up all templates using the template manager service
|
||||
|
|
|
@ -91,7 +91,9 @@
|
|||
"MICROPHONE": "麦克风",
|
||||
"SCREEN": "屏幕",
|
||||
"NO_STREAMS": "无",
|
||||
"YOU": "你"
|
||||
"YOU": "你",
|
||||
"MUTE": "静音",
|
||||
"UNMUTE": "取消静音"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "设置",
|
||||
|
|
|
@ -90,7 +90,9 @@
|
|||
"MICROPHONE": "MIKROFON",
|
||||
"SCREEN": "BILDSCHIRM",
|
||||
"NO_STREAMS": "KEINE",
|
||||
"YOU": "Sie"
|
||||
"YOU": "Sie",
|
||||
"MUTE": "Stummschalten",
|
||||
"UNMUTE": "Stummschaltung aufheben"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "Einstellungen",
|
||||
|
|
|
@ -91,7 +91,9 @@
|
|||
"MICROPHONE": "MICROPHONE",
|
||||
"SCREEN": "SCREEN",
|
||||
"NO_STREAMS": "NONE",
|
||||
"YOU": "You"
|
||||
"YOU": "You",
|
||||
"MUTE": "Mute",
|
||||
"UNMUTE": "Unmute"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "Settings",
|
||||
|
|
|
@ -91,7 +91,9 @@
|
|||
"MICROPHONE": "MICRÓFONO",
|
||||
"SCREEN": "PANTALLA",
|
||||
"NO_STREAMS": "NINGUNO",
|
||||
"YOU": "Tú"
|
||||
"YOU": "Tú",
|
||||
"MUTE": "Silenciar",
|
||||
"UNMUTE": "Activar audio"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "Configuración",
|
||||
|
|
|
@ -91,7 +91,9 @@
|
|||
"MICROPHONE": "MICROPHONE",
|
||||
"SCREEN": "ÉCRAN",
|
||||
"NO_STREAMS": "PAS_DE_FLUX",
|
||||
"YOU": "Vous"
|
||||
"YOU": "Vous",
|
||||
"MUTE": "Couper le son",
|
||||
"UNMUTE": "Désactiver le son"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "Paramètres",
|
||||
|
|
|
@ -91,7 +91,9 @@
|
|||
"MICROPHONE": "माइक्रोफ़ोन",
|
||||
"SCREEN": "स्क्रीन",
|
||||
"NO_STREAMS": "कोई_स्ट्रीम_नहीं",
|
||||
"YOU": "आप"
|
||||
"YOU": "आप",
|
||||
"MUTE": "मौन",
|
||||
"UNMUTE": "अनमौन"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "सेटिंग्स",
|
||||
|
|
|
@ -91,7 +91,9 @@
|
|||
"MICROPHONE": "MICROFONO",
|
||||
"SCREEN": "SCREEN",
|
||||
"NO_STREAMS": "NESSUNO",
|
||||
"YOU": "Tu"
|
||||
"YOU": "Tu",
|
||||
"MUTE": "Disattiva l'audio",
|
||||
"UNMUTE": "Attiva l'audio"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "Impostazioni",
|
||||
|
|
|
@ -91,7 +91,9 @@
|
|||
"MICROPHONE": "マイクロフォン",
|
||||
"SCREEN": "スクリーン",
|
||||
"NO_STREAMS": "ストリームなし",
|
||||
"YOU": "あなた"
|
||||
"YOU": "あなた",
|
||||
"MUTE": "ミュート",
|
||||
"UNMUTE": "ミュート解除"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "設定",
|
||||
|
|
|
@ -91,7 +91,9 @@
|
|||
"MICROPHONE": "MICROFOON",
|
||||
"SCREEN": "SCHERM",
|
||||
"NO_STREAMS": "GEEN",
|
||||
"YOU": "Jij"
|
||||
"YOU": "Jij",
|
||||
"MUTE": "Dempen",
|
||||
"UNMUTE": "Dempen opheffen"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "Instellingen",
|
||||
|
|
|
@ -91,7 +91,9 @@
|
|||
"MICROPHONE": "MICROFONE",
|
||||
"SCREEN": "TELA",
|
||||
"NO_STREAMS": "NENHUM",
|
||||
"YOU": "Você (eu)"
|
||||
"YOU": "Você (eu)",
|
||||
"MUTE": "Silenciar",
|
||||
"UNMUTE": "Ativar som"
|
||||
},
|
||||
"SETTINGS": {
|
||||
"TITLE": "Configurações",
|
||||
|
|
Loading…
Reference in New Issue