1313 let gridCellsState = Array ( MAX_GRID_SIZE ) . fill ( null ) ;
1414 let fullscreenCellIndex = null ;
1515
16+ function updatePlaceholdersLanguage ( ) {
17+ const placeholderHTML = `<span><i class="material-icons placeholder-icon">add_photo_alternate</i><br>${ App . t ( 'drop_camera_here' ) } </span>` ;
18+
19+ for ( let i = 0 ; i < gridCellsState . length ; i ++ ) {
20+ if ( gridCellsState [ i ] === null ) {
21+ const cell = gridContainer . querySelector ( `[data-cell-id='${ i } ']` ) ;
22+ if ( cell ) {
23+ cell . innerHTML = placeholderHTML ;
24+ }
25+ }
26+ }
27+ }
28+
1629 function getGridSize ( ) {
1730 return { cols : gridCols , rows : gridRows } ;
1831 }
3447 btn . className = 'layout-btn' ;
3548 btn . dataset . layout = layout ;
3649 btn . textContent = layout . split ( 'x' ) . reduce ( ( a , b ) => a * b , 1 ) ;
37- btn . title = `Раскладка ${ layout } ` ;
50+ btn . title = `Layout ${ layout } ` ;
3851 btn . onclick = ( ) => {
3952 const [ cols , rows ] = layout . split ( 'x' ) . map ( Number ) ;
4053 setGridLayout ( cols , rows ) ;
109122 cell . style . display = 'none' ;
110123 cell . ondblclick = ( ) => toggleFullscreen ( i ) ;
111124
112- cell . innerHTML = `<span><i class="material-icons placeholder-icon">add_photo_alternate</i><br>Перетащите камеру </span>` ;
125+ cell . innerHTML = `<span><i class="material-icons placeholder-icon">add_photo_alternate</i><br>${ App . t ( 'drop_camera_here' ) } </span>` ;
113126
114127 cell . addEventListener ( 'dragover' , ( e ) => { e . preventDefault ( ) ; cell . classList . add ( 'drag-over' ) ; } ) ;
115128 cell . addEventListener ( 'dragleave' , ( ) => cell . classList . remove ( 'drag-over' ) ) ;
184197 sourceCell . classList . toggle ( 'active' , ! ! sourceState ) ;
185198 targetCell . classList . toggle ( 'active' , ! ! targetState ) ;
186199
187- const placeholderHTML = `<span><i class="material-icons placeholder-icon">add_photo_alternate</i><br>Перетащите камеру </span>` ;
200+ const placeholderHTML = `<span><i class="material-icons placeholder-icon">add_photo_alternate</i><br>${ App . t ( 'drop_camera_here' ) } </span>` ;
188201 if ( ! sourceState ) sourceCell . innerHTML = placeholderHTML ;
189202 if ( ! targetState ) targetCell . innerHTML = placeholderHTML ;
190203
204217 const cellElement = document . querySelector ( `[data-cell-id='${ cellIndex } ']` ) ;
205218 if ( ! cellElement ) return ;
206219
207- cellElement . innerHTML = `<span>Подключение... </span>` ;
220+ cellElement . innerHTML = `<span>${ App . t ( 'connecting' ) } </span>` ;
208221 cellElement . classList . add ( 'active' ) ;
209222 cellElement . draggable = true ;
210223 setupDragStartForCell ( cellElement , cellIndex ) ;
239252 cellElement . appendChild ( nameDiv ) ;
240253 cellElement . appendChild ( statsDiv ) ;
241254
242- // ИЗМЕНЕНИЕ ЗДЕСЬ: добавлен onVideoDecode
243255 const player = new JSMpeg . Player ( `ws://localhost:${ result . wsPort } ` , {
244256 canvas,
245257 autoplay : true ,
276288
277289 gridCellsState [ cellIndex ] . player = player ;
278290 } else {
279- cellElement . innerHTML = `<span>Ошибка : ${ result . error || 'Неизвестная ошибка' } </span>` ;
291+ cellElement . innerHTML = `<span>${ App . t ( 'error' ) } : ${ result . error || App . t ( 'unknown_error' ) } </span>` ;
280292 cellElement . classList . remove ( 'active' ) ;
281293 cellElement . draggable = false ;
282294 gridCellsState [ cellIndex ] = null ;
306318 if ( clearCellUI ) {
307319 const cellElement = document . querySelector ( `[data-cell-id='${ cellIndex } ']` ) ;
308320 if ( cellElement ) {
309- cellElement . innerHTML = `<span><i class="material-icons placeholder-icon">add_photo_alternate</i><br>Перетащите камеру </span>` ;
321+ cellElement . innerHTML = `<span><i class="material-icons placeholder-icon">add_photo_alternate</i><br>${ App . t ( 'drop_camera_here' ) } </span>` ;
310322 cellElement . classList . remove ( 'active' ) ;
311323 cellElement . draggable = false ;
312324 }
323335
324336 await destroyPlayerInCell ( cellIndex ) ;
325337 const cellElement = document . querySelector ( `[data-cell-id='${ cellIndex } ']` ) ;
326- if ( cellElement ) cellElement . innerHTML = ' <span>Переключение потока... </span>' ;
338+ if ( cellElement ) cellElement . innerHTML = ` <span>${ App . t ( 'switch_stream' ) } </span>` ;
327339
328340 await startStreamInCell ( cellIndex , cameraId , newStreamId ) ;
329341
346358 const currentVolume = state . player ? state . player . volume : 0 ;
347359
348360 await destroyPlayerInCell ( cellIndex ) ;
349- cell . innerHTML = ' <span>Переключение... </span>' ;
361+ cell . innerHTML = ` <span>${ App . t ( 'switch_fullscreen' ) } </span>` ;
350362
351363 if ( isCurrentlyFullscreen ) {
352364 fullscreenCellIndex = null ;
380392 const { camera, streamId } = gridCellsState [ cellIndex ] ;
381393 const cellElement = document . querySelector ( `[data-cell-id='${ cellIndex } ']` ) ;
382394 if ( cellElement ) {
383- cellElement . innerHTML = `<span>Потеря связи.<br>Переподключение через 5с... </span>` ;
395+ cellElement . innerHTML = `<span>${ App . t ( 'stream_died_reconnecting' ) } </span>` ;
384396 cellElement . classList . remove ( 'active' ) ;
385397 cellElement . draggable = false ;
386398 }
442454 const state = gridCellsState [ cellIndex ] ;
443455 if ( state && state . camera ) {
444456 e . preventDefault ( ) ;
445- window . api . showCameraContextMenu ( state . camera . id ) ;
457+ const labels = {
458+ files : `🗂️ ${ App . t ( 'context_file_manager' ) } ` ,
459+ ssh : `💻 ${ App . t ( 'context_ssh' ) } ` ,
460+ settings : `⚙️ ${ App . t ( 'context_settings' ) } ` ,
461+ edit : `✏️ ${ App . t ( 'context_edit' ) } ` ,
462+ delete : `🗑️ ${ App . t ( 'context_delete' ) } `
463+ } ;
464+ window . api . showCameraContextMenu ( { cameraId : state . camera . id , labels } ) ;
446465 }
447466 } ) ;
448467 window . addEventListener ( 'keydown' , ( e ) => {
462481 updateRecordingState,
463482 restartStreamsForCamera,
464483 updateCameraNameInGrid,
465- removeStreamsForCamera
484+ removeStreamsForCamera,
485+ updatePlaceholdersLanguage
466486 }
467487 }
468488} ) ( window ) ;
0 commit comments