// Drone Task Manager - I18n (zh/en/ru)
(function() {
  'use strict';

  const I18N = {
    zh: {
      sys_status: '系统状态', app_market: 'App 市场', task_market: '任务市场',
      task_config: '任务配置', running_instances: '运行实例', history: '历史任务',
      refresh: '刷新', cleanup_history: '清理历史',
      upload_hint: '拖放 .lldtp 文件到此处，或 <span class="upload-link">点击选择</span>',
      updater_hint: '拖放压缩包到此处，或 <span class="upload-link">点击选择</span>',
      back: '返回', start_task: '启动任务', params_count: '个参数',
      running_instance_alert: '任务 "{name}" 已有运行中的实例 ({id})\n请先停止现有实例再启动新任务。',
      enable: '启用', browse: '浏览...', range: '范围', action: '操作',
      param_validation_failed: '参数校验失败', no_instances: '暂无实例',
      result: '结果', files: '文件', interrupted: '上次意外中断',
      restart_hint: '该任务在系统断电或崩溃前正在运行，是否使用相同参数重新启动？',
      restart: '重新启动', finished: '完成', running: '运行', stopped: '已停止', duration: '耗时',
      stop: '停止', delete: '删除', edit: '编辑', reboot: '重启', logs: '日志', download: '下载', upload: '上传',
      stop_failed: '停止失败', confirm_delete: '确定删除该实例记录？',
      confirm_delete_file: '确定删除以下文件或目录？',
      confirm_restart: '确定重新启动任务 "{name}"？', reload_failed: '重新启动失败',
      loading: '加载中...', load_log_failed: '加载日志失败',
      version: '版本', build: '构建', drone: '无人机', cpu: 'CPU', memory: '内存', disk: '磁盘', timestamp: '时间(UTC)', system_uptime: '系统运行', process_uptime: '程序运行',
      load_history_failed: '加载失败', no_history: '暂无历史记录', file_deleted: '文件已删除',
      keep_history_days: '保留最近多少天的历史记录？',
      cleaned_records: '已清理 {count} 条历史记录', cleanup_failed: '清理失败',
      lock_detected: '检测到锁文件 /tmp/arm.lock，其他进程可能正在运行。\n强制启动可能导致冲突，是否继续？',
      lock_confirm: '再次确认：强制启动可能导致数据冲突或硬件损坏，确定继续？',
      start_failed: '启动失败', starting: '启动中...',
      file_browser_title: '选择文件', fallback_browser: '回退到通用文件浏览',
      file_path_hint: '手动输入路径或点击选择...', load_failed: '无法加载',
      empty_dir: '目录为空', directory: '目录', file_name: '文件名', file_size: '大小', file_mtime: '修改时间', total_size: '目录总大小',
      install_app: '安装 App', lldtp_only: '仅支持 .lldtp 文件',
      install_success: 'App "{name}" ({version}) 安装成功',
      install_failed: '安装失败', load_apps_failed: '无法加载 App 列表',
      no_apps: '暂无已安装 App，请上传 .lldtp 文件', uninstall: '卸载',
      confirm_uninstall: '确定卸载 {name} v{version}?', uninstall_failed: '卸载失败',
      load_defs_failed: '加载任务定义失败', load_instances_failed: '加载实例失败',
      preview: '预览', preview_update_failed: '预览更新失败',
      ws_disconnected: '未连接', ws_connecting: '连接中...', ws_connected: '已连接',
      paging_info: '{total} 条 · 第 {page}/{totalPages} 页',
      prev_page: '上一页', next_page: '下一页', all_apps: '全部应用',
      tab_system: '系统', tab_live: '直播', tab_push: '推流', tab_detect: '检测', tab_market: 'App应用', tab_apps: '安装', tab_files: '文件', tab_updater: '飞控更新', tab_settings: '设置', tab_missions: '航线任务',
      tab_instances: '实例', tab_history: '历史', close: '关闭', save: '保存', saved: '已保存', cancel: '取消', upload_success: '上传成功', upload_failed: '上传失败', upload_progress: '上传中', upload_done: '上传完成',
      settings_api_base: 'API 地址', settings_ws_host: 'WebSocket 地址', settings_hint: '修改后需刷新页面生效', settings_reset: '恢复默认', settings_api_placeholder: '如 http://192.168.1.100:8080', settings_ws_placeholder: '如 192.168.1.100:8080',
      mission_name: '任务名称', mission_images: '图片', mission_videos: '视频', mission_status: '状态', mission_unknown: '未知',
      all: '全部', normal_files: '普通', img_filter: '图片过滤',
      bag_files: '.bag', pcd_files: '.pcd',
      snapshot_files: '.snapshot', traj_files: '.traj', other_files: '其他',
      pack_download: '打包下载', download_zip: '打包（压缩）', download_tar: '打包（快速）',
      no_updates: '暂无可用更新', play: '播放', save_failed: '保存失败',
      default_camera: '默认相机', media_add_stream: '添加流', media_stream_config: '流配置', media_name: '名称', media_source_url: '源地址 (RTSP)', media_codec: '编码',
      media_enabled: '启用', media_disabled: '禁用', media_play: '播放', media_start: '启动', media_stop: '停止',
      no_streams: '暂无流配置', media_connecting: '连接中...', media_playing: '播放中', media_connection_failed: '连接失败',
      media_auto_stop: '起飞时自动停止直播',
      media_start_failed: '启动失败', media_stop_failed: '停止失败', media_takeoff_lock_blocked: '检测到起飞锁，流启动已被阻止',
      push_global_auto: '开机自动推流总开关', push_start_all: '启动全部自启', push_stop_all: '停止全部',
      no_auto_push: '没有可自启的推流配置', no_running_push: '没有运行中的推流',
      push_add: '新增推流', no_push_configs: '暂无推流配置，点击上方按钮新增', auto_start: '自启', disabled: '禁用',
      push_config: '推流配置', push_name: '名称', push_stream_key: '流密钥', push_source_url: '本地源地址',
      push_server_host: '远程服务器', push_server_port: '端口', push_protocol: '协议', push_codec: '编码',
      push_extra_args: '额外参数', push_auto_start: '开机自动启动', push_enabled: '启用',
      push_stop_on_flight: '飞行时自动停止',
      detect_start: '启动检测', detect_stop: '停止检测', detect_settings: '检测设置', detect_stream_url: '视频流地址', detect_output_dir: '保存目录',
      detect_model: 'YOLO 模型', detect_select_model: '请选择模型', detect_confidence: '置信度阈值', detect_interval: '检测间隔（帧）',
      detect_max_images: '最大保留图片数', detect_target_labels: '关心标签（留空表示全部）', detect_enabled: '启用检测',
      detect_auto_start: '开机自动启动', detect_stop_on_flight: '飞行时自动停止', detect_upload_model: '上传模型', detect_stats: '检测统计', detect_alert: '检测到目标！',
      self_update_title: '自我更新', self_update_upload_hint: '拖放 deploy 生成的 tar.gz 包到此处，或 <span class="upload-link">点击选择</span>',
      self_update_packages: '可用更新包', self_update_backups: '历史备份',
      self_update_current_version: '当前版本', self_update_apply: '应用更新', self_update_rollback: '回滚',
      self_update_no_packages: '暂无可用更新包', self_update_no_backups: '暂无备份',
      self_update_confirm_apply: '确定应用以下更新包？服务将重启。',
      self_update_confirm_rollback: '确定回滚到上一个备份版本？服务将重启。',
      self_update_restarting: '更新已启动，服务即将重启，请稍后刷新页面。',
      self_update_apply_failed: '应用更新失败', self_update_rollback_failed: '回滚失败',
      sys_reboot: '重启系统', sys_poweroff: '关机', sys_reboot_confirm: '确定要重启系统吗？', sys_reboot_confirm2: '再次确认：系统将立即重启，所有未保存数据将丢失。', sys_poweroff_confirm: '确定要关闭系统吗？', sys_poweroff_confirm2: '再次确认：系统将立即关机，所有未保存数据将丢失。', sys_rebooting: '系统正在重启...', sys_powering_off: '系统正在关机...',
      tab_services: '服务', service_status: '状态', service_start: '启动', service_stop: '停止', service_restart: '重启', service_active: '运行中', service_inactive: '已停止', service_unknown: '未知', service_control_failed: '操作失败', confirm_stop_service: '确定要{action}服务 {name} 吗？',
      tab_diagnostics: '诊断', diag_title: '系统诊断', diag_run_all: '运行全部', diag_run_selected: '运行选中',
      diag_clear: '清空结果', diag_download: '导出报告', diag_progress: '进度', diag_pass: '通过', diag_fail: '失败',
      diag_pending: '待测试', diag_running: '测试中', diag_total: '总计', diag_summary: '汇总',
      diag_flight_locked: '无人机已解锁/飞行中，禁止运行系统诊断', diag_hint: '请选择测试项并点击"运行全部"或"运行选中"开始诊断',
      diag_completed: '诊断完成', diag_no_session: '会话不存在', diag_select_test: '请至少选择一项测试',
      tab_monitor: '监控', monitor_title: '端口监控', monitor_enable: '启用监控', monitor_running: '监控运行中', monitor_stopped: '监控已停止',
      monitor_network: '网卡', monitor_usb: 'USB 设备', monitor_logs: '日志',
      monitor_no_network: '未检测到网卡', monitor_no_usb: '未检测到 USB 设备', monitor_no_logs: '暂无日志文件',
      monitor_changes: '变化检测', monitor_added: '新增', monitor_removed: '移除', monitor_changed: '变更',
      pack_progress: '打包下载中', pack_failed: '打包失败',
    },
    en: {
      sys_status: 'System Status', app_market: 'App Market', task_market: 'Task Market',
      task_config: 'Task Config', running_instances: 'Running Instances', history: 'History',
      refresh: 'Refresh', cleanup_history: 'Cleanup History',
      upload_hint: 'Drag & drop .lldtp file here, or <span class="upload-link">click to select</span>',
      updater_hint: 'Drop package here, or <span class="upload-link">click to select</span>',
      back: 'Back', start_task: 'Start Task', params_count: ' params',
      running_instance_alert: 'Task "{name}" already has a running instance ({id})\nPlease stop the existing instance before starting a new one.',
      enable: 'Enable', browse: 'Browse...', range: 'Range', action: 'Action',
      param_validation_failed: 'Parameter validation failed', no_instances: 'No instances',
      result: 'Result', files: 'Files', interrupted: 'Interrupted unexpectedly',
      restart_hint: 'This task was running before a power failure or crash. Restart with the same parameters?',
      restart: 'Restart', finished: 'Finished', running: 'Running', stopped: 'Stopped', duration: 'Duration',
      stop: 'Stop', delete: 'Delete', edit: 'Edit', reboot: 'Reboot', logs: 'Logs', download: 'download', upload: 'Upload',
      stop_failed: 'Stop failed', confirm_delete: 'Are you sure to delete this instance record?',
      confirm_delete_file: 'Are you sure to delete this file or directory?',
      confirm_restart: 'Are you sure to restart task "{name}"?', reload_failed: 'Restart failed',
      loading: 'Loading...', load_log_failed: 'Failed to load logs',
      version: 'Version', build: 'Build', drone: 'Drone', cpu: 'CPU', memory: 'Memory', disk: 'Disk', timestamp: 'Time (UTC)', system_uptime: 'System Uptime', process_uptime: 'App Uptime',
      load_history_failed: 'Load failed', no_history: 'No history records', file_deleted: 'File deleted',
      keep_history_days: 'Keep history records for how many days?',
      cleaned_records: 'Cleaned {count} history records', cleanup_failed: 'Cleanup failed',
      lock_detected: 'Lock file /tmp/arm.lock detected. Another process may be running.\nForce start may cause conflicts. Continue?',
      lock_confirm: 'Confirm again: Force start may cause data conflicts or hardware damage. Continue?',
      start_failed: 'Start failed', starting: 'Starting...',
      file_browser_title: 'Select File', fallback_browser: 'Fallback to generic file browser',
      file_path_hint: 'Enter path manually or click to select...', load_failed: 'Unable to load',
      empty_dir: 'Directory is empty', directory: 'Directory', file_name: 'Name', file_size: 'Size', file_mtime: 'Modified', total_size: 'Total Size',
      install_app: 'Install App', lldtp_only: 'Only .lldtp files are supported',
      install_success: 'App "{name}" ({version}) installed successfully',
      install_failed: 'Installation failed', load_apps_failed: 'Unable to load App list',
      no_apps: 'No installed Apps. Please upload a .lldtp file', uninstall: 'Uninstall',
      confirm_uninstall: 'Are you sure to uninstall {name} v{version}?', uninstall_failed: 'Uninstall failed',
      load_defs_failed: 'Failed to load task definitions', load_instances_failed: 'Failed to load instances',
      preview: 'Preview', preview_update_failed: 'Preview update failed',
      ws_disconnected: 'disconnected', ws_connecting: 'connecting...', ws_connected: 'connected',
      paging_info: '{total} entries · Page {page}/{totalPages}',
      prev_page: 'Prev', next_page: 'Next', all_apps: 'All Apps',
      tab_system: 'System', tab_live: 'Live', tab_push: 'Push', tab_detect: 'Detect', tab_market: 'Apps', tab_apps: 'Install', tab_files: 'Files', tab_updater: 'FC Update', tab_settings: 'Settings', tab_missions: 'Missions',
      tab_instances: 'Instances', tab_history: 'History', close: 'Close', save: 'Save', saved: 'Saved', cancel: 'Cancel', upload_success: 'Upload success', upload_failed: 'Upload failed', upload_progress: 'Uploading', upload_done: 'Upload complete',
      settings_api_base: 'API Base URL', settings_ws_host: 'WebSocket Host', settings_hint: 'Refresh page after saving to take effect', settings_reset: 'Reset to Default', settings_api_placeholder: 'e.g. http://192.168.1.100:8080', settings_ws_placeholder: 'e.g. 192.168.1.100:8080',
      mission_name: 'Mission', mission_images: 'Images', mission_videos: 'Videos', mission_status: 'Status', mission_unknown: 'Unknown',
      all: 'All', normal_files: 'Normal', img_filter: 'Image Filter',
      bag_files: '.bag', pcd_files: '.pcd',
      snapshot_files: '.snapshot', traj_files: '.traj', other_files: 'Other',
      pack_download: 'Pack', download_zip: 'Pack (Compress)', download_tar: 'Pack (Fast)',
      no_updates: 'No updates available', play: 'Play', save_failed: 'Save failed',
      default_camera: 'Default Camera', media_add_stream: 'Add Stream', media_stream_config: 'Stream Config', media_name: 'Name', media_source_url: 'Source URL (RTSP)', media_codec: 'Codec',
      media_enabled: 'Enabled', media_disabled: 'Disabled', media_play: 'Play', media_start: 'Start', media_stop: 'Stop',
      no_streams: 'No stream configs', media_connecting: 'Connecting...', media_playing: 'Playing', media_connection_failed: 'Connection failed',
      media_auto_stop: 'Auto-stop live on takeoff',
      media_start_failed: 'Start Failed', media_stop_failed: 'Stop Failed', media_takeoff_lock_blocked: 'Takeoff lock detected, stream start blocked',
      push_global_auto: 'Global auto push', push_start_all: 'Start all auto', push_stop_all: 'Stop all',
      no_auto_push: 'No auto-start configs', no_running_push: 'No running streams',
      push_add: 'Add Push Stream', no_push_configs: 'No push configs. Click button to add.', auto_start: 'Auto', disabled: 'Disabled',
      push_config: 'Push Config', push_name: 'Name', push_stream_key: 'Stream Key', push_source_url: 'Source URL',
      push_server_host: 'Server', push_server_port: 'Port', push_protocol: 'Protocol', push_codec: 'Codec',
      push_extra_args: 'Extra Args', push_auto_start: 'Auto-start', push_enabled: 'Enabled',
      push_stop_on_flight: 'Stop on flight',
      detect_start: 'Start Detection', detect_stop: 'Stop Detection', detect_settings: 'Detection Settings', detect_stream_url: 'Stream URL', detect_output_dir: 'Output Dir',
      detect_model: 'YOLO Model', detect_select_model: 'Select model', detect_confidence: 'Confidence', detect_interval: 'Interval (frames)',
      detect_max_images: 'Max images', detect_target_labels: 'Target labels (empty=all)', detect_enabled: 'Enable Detection',
      detect_auto_start: 'Auto-start on boot', detect_stop_on_flight: 'Stop on flight', detect_upload_model: 'Upload Model', detect_stats: 'Detection Stats', detect_alert: 'Target Detected!',
      self_update_title: 'Self Update', self_update_upload_hint: 'Drop deploy tar.gz here, or <span class="upload-link">click to select</span>',
      self_update_packages: 'Available Packages', self_update_backups: 'Backups',
      self_update_current_version: 'Current Version', self_update_apply: 'Apply Update', self_update_rollback: 'Rollback',
      self_update_no_packages: 'No available update packages', self_update_no_backups: 'No backups',
      self_update_confirm_apply: 'Apply this update package? Service will restart.',
      self_update_confirm_rollback: 'Rollback to the latest backup? Service will restart.',
      self_update_restarting: 'Update started, service will restart shortly. Please refresh later.',
      self_update_apply_failed: 'Apply update failed', self_update_rollback_failed: 'Rollback failed',
      sys_reboot: 'Reboot', sys_poweroff: 'Power Off', sys_reboot_confirm: 'Are you sure to reboot the system?', sys_reboot_confirm2: 'Confirm again: The system will reboot immediately. Unsaved data will be lost.', sys_poweroff_confirm: 'Are you sure to shut down the system?', sys_poweroff_confirm2: 'Confirm again: The system will shut down immediately. Unsaved data will be lost.', sys_rebooting: 'System is rebooting...', sys_powering_off: 'System is shutting down...',
      tab_services: 'Services', service_status: 'Status', service_start: 'Start', service_stop: 'Stop', service_restart: 'Restart', service_active: 'Active', service_inactive: 'Inactive', service_unknown: 'Unknown', service_control_failed: 'Operation failed', confirm_stop_service: 'Are you sure to {action} service {name}?',
      tab_diagnostics: 'Diagnostics', diag_title: 'System Diagnostics', diag_run_all: 'Run All', diag_run_selected: 'Run Selected',
      diag_clear: 'Clear Results', diag_download: 'Export Report', diag_progress: 'Progress', diag_pass: 'Pass', diag_fail: 'Fail',
      diag_pending: 'Pending', diag_running: 'Running', diag_total: 'Total', diag_summary: 'Summary',
      diag_flight_locked: 'Drone is armed/in flight. System diagnostics are prohibited.', diag_hint: 'Select tests and click "Run All" or "Run Selected" to start diagnostics',
      diag_completed: 'Diagnostics completed', diag_no_session: 'Session not found', diag_select_test: 'Please select at least one test',
      tab_monitor: 'Monitor', monitor_title: 'Port Monitor', monitor_enable: 'Enable Monitor', monitor_running: 'Monitoring', monitor_stopped: 'Stopped',
      monitor_network: 'Network', monitor_usb: 'USB Devices', monitor_logs: 'Logs',
      monitor_no_network: 'No network interfaces detected', monitor_no_usb: 'No USB devices detected', monitor_no_logs: 'No log files',
      monitor_changes: 'Changes', monitor_added: 'Added', monitor_removed: 'Removed', monitor_changed: 'Changed',
      pack_progress: 'Packing...', pack_failed: 'Pack failed',
    },
    ru: {
      sys_status: 'Состояние системы', app_market: 'Рынок приложений', task_market: 'Рынок задач',
      task_config: 'Настройка задачи', running_instances: 'Запущенные экземпляры', history: 'История',
      refresh: 'Обновить', cleanup_history: 'Очистить историю',
      upload_hint: 'Перетащите файл .lldtp сюда или <span class="upload-link">нажмите для выбора</span>',
      updater_hint: 'Перетащите пакет сюда или <span class="upload-link">нажмите для выбора</span>',
      back: 'Назад', start_task: 'Запустить задачу', params_count: ' параметров',
      running_instance_alert: 'Задача "{name}" уже имеет запущенный экземпляр ({id})\nОстановите существующий экземпляр перед запуском новой задачи.',
      enable: 'Включить', browse: 'Обзор...', range: 'Диапазон', action: 'Действие',
      param_validation_failed: 'Ошибка проверки параметров', no_instances: 'Нет экземпляров',
      result: 'Результат', files: 'Файлы', interrupted: 'Непредвиденное прерывание',
      restart_hint: 'Эта задача выполнялась до отключения питания или сбоя. Перезапустить с теми же параметрами?',
      restart: 'Перезапустить', finished: 'Завершено', running: 'Выполняется', stopped: 'Остановлено', duration: 'Длительность',
      stop: 'Остановить', delete: 'Удалить', edit: 'Редактировать', reboot: 'Перезагрузить', logs: 'Журналы', download: 'Скачать', upload: 'Загрузить',
      stop_failed: 'Ошибка остановки', confirm_delete: 'Удалить запись об этом экземпляре?',
      confirm_delete_file: 'Удалить этот файл или каталог?',
      confirm_restart: 'Перезапустить задачу "{name}"?', reload_failed: 'Ошибка перезапуска',
      loading: 'Загрузка...', load_log_failed: 'Ошибка загрузки журналов',
      version: 'Версия', build: 'Сборка', drone: 'Дрон', cpu: 'ЦП', memory: 'Память', disk: 'Диск', timestamp: 'Время (UTC)', system_uptime: 'Время работы системы', process_uptime: 'Время работы приложения',
      load_history_failed: 'Ошибка загрузки', no_history: 'Нет записей в истории', file_deleted: 'Файл удалён',
      keep_history_days: 'Сохранить записи истории за сколько дней?',
      cleaned_records: 'Очищено {count} записей истории', cleanup_failed: 'Ошибка очистки',
      lock_detected: 'Обнаружен файл блокировки /tmp/arm.lock. Возможно, другой процесс выполняется.\nПринудительный запуск может вызвать конфликты. Продолжить?',
      lock_confirm: 'Подтвердите ещё раз: принудительный запуск может вызвать конфликты данных или повреждение оборудования. Продолжить?',
      start_failed: 'Ошибка запуска', starting: 'Запуск...',
      file_browser_title: 'Выбрать файл', fallback_browser: 'Переход к универсальному файловому браузеру',
      file_path_hint: 'Введите путь вручную или нажмите для выбора...', load_failed: 'Не удалось загрузить',
      empty_dir: 'Папка пуста', directory: 'Папка', file_name: 'Имя', file_size: 'Размер', file_mtime: 'Дата', total_size: 'Общий размер',
      install_app: 'Установить приложение', lldtp_only: 'Поддерживаются только файлы .lldtp',
      install_success: 'Приложение "{name}" ({version}) успешно установлено',
      install_failed: 'Ошибка установки', load_apps_failed: 'Не удалось загрузить список приложений',
      no_apps: 'Нет установленных приложений. Загрузите файл .lldtp', uninstall: 'Удалить',
      confirm_uninstall: 'Удалить {name} v{version}?', uninstall_failed: 'Ошибка удаления',
      load_defs_failed: 'Ошибка загрузки определений задач', load_instances_failed: 'Ошибка загрузки экземпляров',
      preview: 'Предпросмотр', preview_update_failed: 'Ошибка обновления предпросмотра',
      ws_disconnected: 'отключено', ws_connecting: 'подключение...', ws_connected: 'подключено',
      paging_info: '{total} записей · Стр. {page}/{totalPages}',
      prev_page: 'Назад', next_page: 'Вперёд', all_apps: 'Все приложения',
      tab_system: 'Система', tab_live: 'Live', tab_push: 'Push', tab_detect: 'Детекция', tab_market: 'Приложения', tab_apps: 'Установка', tab_files: 'Файлы', tab_updater: 'Обновление FC', tab_settings: 'Настройки', tab_missions: 'Маршруты',
      tab_instances: 'Экземпляры', tab_history: 'История', close: 'Закрыть', save: 'Сохранить', saved: 'Сохранено', cancel: 'Отмена', upload_success: 'Загружено', upload_failed: 'Ошибка загрузки', upload_progress: 'Загрузка', upload_done: 'Загрузка завершена',
      all: 'Все', normal_files: 'Обычные', img_filter: 'Фильтр изображений',
      bag_files: '.bag', pcd_files: '.pcd',
      snapshot_files: '.snapshot', traj_files: '.traj', other_files: 'Другие',
      pack_download: 'Скачать архив', download_zip: 'Архив (Сжатие)', download_tar: 'Архив (Быстрый)',
      no_updates: 'Нет доступных обновлений', play: 'Воспроизвести', save_failed: 'Ошибка сохранения',
      sys_reboot: 'Перезагрузить', sys_poweroff: 'Выключить', sys_reboot_confirm: 'Вы уверены, что хотите перезагрузить систему?', sys_reboot_confirm2: 'Подтвердите ещё раз: система немедленно перезагрузится. Несохранённые данные будут потеряны.', sys_poweroff_confirm: 'Вы уверены, что хотите выключить систему?', sys_poweroff_confirm2: 'Подтвердите ещё раз: система немедленно выключится. Несохранённые данные будут потеряны.', sys_rebooting: 'Система перезагружается...', sys_powering_off: 'Система выключается...',
      tab_services: 'Службы', service_status: 'Статус', service_start: 'Запуск', service_stop: 'Остановка', service_restart: 'Перезапуск', service_active: 'Активна', service_inactive: 'Неактивна', service_unknown: 'Неизвестно', service_control_failed: 'Ошибка операции', confirm_stop_service: 'Вы уверены, что хотите {action} службу {name}?',
      tab_diagnostics: 'Диагностика', diag_title: 'Системная диагностика', diag_run_all: 'Запустить все', diag_run_selected: 'Запустить выбранные',
      diag_clear: 'Очистить результаты', diag_download: 'Экспорт отчёта', diag_progress: 'Прогресс', diag_pass: 'Пройдено', diag_fail: 'Не пройдено',
      diag_pending: 'Ожидание', diag_running: 'Выполняется', diag_total: 'Всего', diag_summary: 'Сводка',
      diag_flight_locked: 'Дрон взведён/в полёте. Системная диагностика запрещена.', diag_hint: 'Выберите тесты и нажмите «Запустить все» или «Запустить выбранные»',
      diag_completed: 'Диагностика завершена', diag_no_session: 'Сессия не найдена', diag_select_test: 'Выберите хотя бы один тест',
      default_camera: 'Камера по умолчанию', media_add_stream: 'Добавить поток', media_stream_config: 'Настройки потока', media_name: 'Название', media_source_url: 'URL источника (RTSP)', media_codec: 'Кодек',
      media_enabled: 'Включено', media_disabled: 'Отключено', media_play: 'Воспроизвести', media_start: 'Запустить', media_stop: 'Остановить',
      no_streams: 'Нет настроек потока', media_connecting: 'Подключение...', media_playing: 'Воспроизведение', media_connection_failed: 'Ошибка подключения',
      media_auto_stop: 'Авто-остановка при взлете',
      media_start_failed: 'Ошибка запуска', media_stop_failed: 'Ошибка остановки', media_takeoff_lock_blocked: 'Обнаружена блокировка взлета, запуск потока заблокирован',
      push_global_auto: 'Авто-пуш при загрузке', push_start_all: 'Запустить все', push_stop_all: 'Остановить все',
      no_auto_push: 'Нет автозапуска', no_running_push: 'Нет активных',
      push_add: 'Добавить', no_push_configs: 'Нет настроек. Нажмите кнопку.', auto_start: 'Авто', disabled: 'Откл.',
      push_config: 'Настройки пуша', push_name: 'Название', push_stream_key: 'Ключ потока', push_source_url: 'Источник',
      push_server_host: 'Сервер', push_server_port: 'Порт', push_protocol: 'Протокол', push_codec: 'Кодек',
      push_extra_args: 'Доп. параметры', push_auto_start: 'Автозапуск', push_enabled: 'Включено',
      push_stop_on_flight: 'Стоп при полёте',
      detect_start: 'Запуск', detect_stop: 'Остановка', detect_settings: 'Настройки', detect_stream_url: 'URL потока', detect_output_dir: 'Папка вывода',
      detect_model: 'Модель YOLO', detect_select_model: 'Выберите модель', detect_confidence: 'Порог', detect_interval: 'Интервал (кадры)',
      detect_max_images: 'Макс. изображений', detect_target_labels: 'Метки (пусто=все)', detect_enabled: 'Включить детекцию',
      detect_auto_start: 'Автозапуск', detect_stop_on_flight: 'Стоп при полёте', detect_upload_model: 'Загрузить модель', detect_stats: 'Статистика', detect_alert: 'Цель обнаружена!',
      self_update_title: 'Самообновление', self_update_upload_hint: 'Перетащите tar.gz сюда или <span class="upload-link">нажмите для выбора</span>',
      self_update_packages: 'Доступные пакеты', self_update_backups: 'Резервные копии',
      self_update_current_version: 'Текущая версия', self_update_apply: 'Применить обновление', self_update_rollback: 'Откат',
      self_update_no_packages: 'Нет доступных пакетов', self_update_no_backups: 'Нет резервных копий',
      self_update_confirm_apply: 'Применить этот пакет обновления? Служба перезапустится.',
      self_update_confirm_rollback: 'Откатить к последней резервной копии? Служба перезапустится.',
      self_update_restarting: 'Обновление запущено, служба скоро перезапустится. Обновите страницу позже.',
      self_update_apply_failed: 'Ошибка применения обновления', self_update_rollback_failed: 'Ошибка отката',
      settings_api_base: 'API адрес', settings_ws_host: 'WebSocket адрес', settings_hint: 'Обновите страницу после сохранения', settings_reset: 'Сбросить', settings_api_placeholder: 'напр. http://192.168.1.100:8080', settings_ws_placeholder: 'напр. 192.168.1.100:8080',
      mission_name: 'Маршрут', mission_images: 'Изображения', mission_videos: 'Видео', mission_status: 'Статус', mission_unknown: 'Неизвестно',
      tab_monitor: 'Монитор', monitor_title: 'Монитор портов', monitor_enable: 'Включить мониторинг', monitor_running: 'Мониторинг активен', monitor_stopped: 'Остановлен',
      monitor_network: 'Сеть', monitor_usb: 'USB-устройства', monitor_logs: 'Журналы',
      monitor_no_network: 'Сетевые интерфейсы не обнаружены', monitor_no_usb: 'USB-устройства не обнаружены', monitor_no_logs: 'Нет файлов журналов',
      monitor_changes: 'Изменения', monitor_added: 'Добавлено', monitor_removed: 'Удалено', monitor_changed: 'Изменено',
      pack_progress: 'Упаковка...', pack_failed: 'Ошибка упаковки',
    }
  };

  function getLang() {
    const saved = localStorage.getItem('dtm-lang');
    if (saved && I18N[saved]) return saved;
    const nav = navigator.language || navigator.userLanguage || 'zh';
    if (nav.startsWith('en')) return 'en';
    if (nav.startsWith('ru')) return 'ru';
    return 'zh';
  }

  window.currentLang = getLang();

  window.t = function(key, vars) {
    let text = (I18N[window.currentLang] && I18N[window.currentLang][key]) || (I18N['zh'] && I18N['zh'][key]) || key;
    if (vars) {
      Object.keys(vars).forEach(function(k) {
        text = text.replace(new RegExp('{' + k + '}', 'g'), vars[k]);
      });
    }
    return text;
  };

  window.setLang = function(lang) {
    if (!I18N[lang]) return;
    window.currentLang = lang;
    localStorage.setItem('dtm-lang', lang);
    if (window.loadDefinitions) window.loadDefinitions();
    if (window.loadInstances) window.loadInstances();
    if (window.loadApps) window.loadApps();
    if (window.updateStaticTexts) window.updateStaticTexts();
  };

  window.updateStaticTexts = function() {
    document.querySelectorAll('[data-i18n]').forEach(function(el) {
      var key = el.getAttribute('data-i18n');
      if (!key) return;
      var text = window.t(key);
      // 翻译值可能包含 HTML（如 upload_hint 中的 <span class="upload-link">）
      el.innerHTML = text;
    });
    var sel = document.getElementById('lang-select');
    if (sel) sel.value = window.currentLang;
  };

  document.addEventListener('DOMContentLoaded', function() {
    var sel = document.getElementById('lang-select');
    if (sel) {
      sel.value = window.currentLang;
      sel.addEventListener('change', function(e) { window.setLang(e.target.value); });
    }
    window.updateStaticTexts();
  });

})();
