diff --git a/server/src/wled_controller/core/processing/notification_stream.py b/server/src/wled_controller/core/processing/notification_stream.py
index f34a93d..0806ba2 100644
--- a/server/src/wled_controller/core/processing/notification_stream.py
+++ b/server/src/wled_controller/core/processing/notification_stream.py
@@ -68,9 +68,9 @@ class NotificationColorStripStream(ColorStripStream):
self._notification_effect = getattr(source, "notification_effect", "flash")
self._duration_ms = max(100, int(getattr(source, "duration_ms", 1500)))
self._default_color = getattr(source, "default_color", "#FFFFFF")
- self._app_colors = dict(getattr(source, "app_colors", {}))
+ self._app_colors = {k.lower(): v for k, v in dict(getattr(source, "app_colors", {})).items()}
self._app_filter_mode = getattr(source, "app_filter_mode", "off")
- self._app_filter_list = list(getattr(source, "app_filter_list", []))
+ self._app_filter_list = [a.lower() for a in getattr(source, "app_filter_list", [])]
self._auto_size = not getattr(source, "led_count", 0)
self._led_count = getattr(source, "led_count", 0) if getattr(source, "led_count", 0) > 0 else 1
with self._colors_lock:
@@ -86,9 +86,12 @@ class NotificationColorStripStream(ColorStripStream):
Returns:
True if the notification was accepted, False if filtered out.
"""
+ # Normalize app name for case-insensitive matching
+ app_lower = app_name.lower() if app_name else None
+
# Check app filter
- if app_name and self._app_filter_mode != "off":
- in_list = app_name in self._app_filter_list
+ if app_lower and self._app_filter_mode != "off":
+ in_list = app_lower in self._app_filter_list
if self._app_filter_mode == "whitelist" and not in_list:
return False
if self._app_filter_mode == "blacklist" and in_list:
@@ -97,8 +100,8 @@ class NotificationColorStripStream(ColorStripStream):
# Resolve color: override > app_colors[app_name] > default_color
if color_override:
color = _hex_to_rgb(color_override)
- elif app_name and app_name in self._app_colors:
- color = _hex_to_rgb(self._app_colors[app_name])
+ elif app_lower and app_lower in self._app_colors:
+ color = _hex_to_rgb(self._app_colors[app_lower])
else:
color = _hex_to_rgb(self._default_color)
diff --git a/server/src/wled_controller/static/css/automations.css b/server/src/wled_controller/static/css/automations.css
index 5bc5884..828dd25 100644
--- a/server/src/wled_controller/static/css/automations.css
+++ b/server/src/wled_controller/static/css/automations.css
@@ -100,6 +100,98 @@
color: var(--text-muted);
}
+/* ── Time-of-Day picker ────────────────────────────────────── */
+
+.time-range-picker {
+ display: flex;
+ align-items: stretch;
+ gap: 0;
+ background: var(--bg-color);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-md);
+ overflow: hidden;
+ transition: border-color var(--duration-fast) ease;
+}
+.time-range-picker:focus-within {
+ border-color: var(--primary-color);
+ box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.15);
+}
+
+.time-range-slot {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 10px 12px 8px;
+ position: relative;
+}
+.time-range-slot + .time-range-slot {
+ border-left: 1px solid var(--border-color);
+}
+
+.time-range-label {
+ font-size: 0.65rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+ color: var(--text-muted);
+ margin-bottom: 6px;
+}
+
+.time-range-input-wrap {
+ display: flex;
+ align-items: center;
+ gap: 2px;
+}
+
+.time-range-input-wrap input[type="number"] {
+ width: 2.4ch;
+ text-align: center;
+ font-size: 1.5rem;
+ font-weight: 600;
+ font-variant-numeric: tabular-nums;
+ font-family: inherit;
+ background: var(--bg-secondary);
+ border: 1px solid transparent;
+ border-radius: var(--radius-sm);
+ color: var(--text-color);
+ padding: 4px 2px;
+ -moz-appearance: textfield;
+ transition: border-color var(--duration-fast) ease,
+ background var(--duration-fast) ease;
+}
+.time-range-input-wrap input[type="number"]::-webkit-inner-spin-button,
+.time-range-input-wrap input[type="number"]::-webkit-outer-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+.time-range-input-wrap input[type="number"]:focus {
+ outline: none;
+ border-color: var(--primary-color);
+ background: color-mix(in srgb, var(--primary-color) 8%, var(--bg-secondary));
+}
+
+.time-range-colon {
+ font-size: 1.4rem;
+ font-weight: 700;
+ color: var(--text-muted);
+ line-height: 1;
+ padding: 0 1px;
+ user-select: none;
+}
+
+.time-range-arrow {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0 6px;
+ color: var(--text-muted);
+ font-size: 1.1rem;
+ align-self: center;
+ user-select: none;
+}
+
+
.condition-field select,
.condition-field textarea {
width: 100%;
@@ -139,55 +231,6 @@
background: rgba(33, 150, 243, 0.1);
}
-.process-picker {
- margin-top: 6px;
- border: 1px solid var(--border-color);
- border-radius: 4px;
- overflow: hidden;
-}
-
-.process-picker-search {
- width: 100%;
- padding: 6px 8px;
- border: none;
- border-bottom: 1px solid var(--border-color);
- background: var(--bg-color);
- color: var(--text-color);
- font-size: 0.85rem;
- font-family: inherit;
- outline: none;
- box-sizing: border-box;
-}
-
-.process-picker-list {
- max-height: 160px;
- overflow-y: auto;
-}
-
-.process-picker-item {
- padding: 4px 8px;
- font-size: 0.8rem;
- cursor: pointer;
- transition: background 0.1s;
-}
-
-.process-picker-item:hover {
- background: rgba(33, 150, 243, 0.15);
-}
-
-.process-picker-item.added {
- color: var(--text-muted);
- cursor: default;
- opacity: 0.6;
-}
-
-.process-picker-loading {
- padding: 8px;
- font-size: 0.8rem;
- color: var(--text-muted);
- text-align: center;
-}
-
/* Webhook URL row */
.webhook-url-row {
display: flex;
diff --git a/server/src/wled_controller/static/css/modal.css b/server/src/wled_controller/static/css/modal.css
index 13eeb78..a8096f8 100644
--- a/server/src/wled_controller/static/css/modal.css
+++ b/server/src/wled_controller/static/css/modal.css
@@ -1403,8 +1403,8 @@
}
.notif-app-color-row .notif-app-color {
- width: 36px;
- height: 32px;
+ width: 28px;
+ height: 28px;
border: 1px solid var(--border-color);
border-radius: 4px;
padding: 1px;
@@ -1413,14 +1413,40 @@
flex-shrink: 0;
}
+.notif-app-browse,
.notif-app-color-remove {
- font-size: 0.7rem;
- padding: 0 4px;
+ background: none;
+ border: 1px solid var(--border-color);
+ color: var(--text-muted);
+ border-radius: 4px;
+ cursor: pointer;
+ padding: 0;
+ width: 28px;
+ height: 28px;
min-width: unset;
- height: 32px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ transition: border-color 0.2s, color 0.2s;
+}
+
+.notif-app-browse svg {
+ width: 14px;
+ height: 14px;
+}
+
+.notif-app-color-remove {
+ font-size: 0.75rem;
line-height: 1;
}
+.notif-app-browse:hover,
+.notif-app-color-remove:hover {
+ border-color: var(--primary-color);
+ color: var(--text-color);
+}
+
/* ── Notification history list ─────────────────────────────────── */
.notif-history-row {
diff --git a/server/src/wled_controller/static/js/core/process-picker.ts b/server/src/wled_controller/static/js/core/process-picker.ts
index 71cbaf8..5146d8f 100644
--- a/server/src/wled_controller/static/js/core/process-picker.ts
+++ b/server/src/wled_controller/static/js/core/process-picker.ts
@@ -1,97 +1,330 @@
/**
- * Shared process picker — reusable UI for browsing running processes
- * and adding them to a textarea (one app per line).
+ * Command-palette style name picker — reusable UI for browsing a list of
+ * names fetched from any API endpoint. Mirrors the EntityPalette pattern.
+ *
+ * Two concrete pickers are exported:
+ *
+ * - **ProcessPalette** — picks from running OS processes (`/system/processes`)
+ * - **NotificationAppPalette** — picks from OS notification history apps
+ *
+ * Both support single-select (returns one value) and multi-select (appends to
+ * a textarea).
*
* Usage:
- * import { attachProcessPicker } from '../core/process-picker.ts';
- * attachProcessPicker(containerEl, textareaEl);
*
- * The container must already contain:
- *
- *
+ * // Single-select
+ * const name = await ProcessPalette.pick({ current: '…', placeholder: '…' });
+ *
+ * // Multi-select (appends to textarea, stays open)
+ * await ProcessPalette.pickMulti({ textarea: el, placeholder: '…' });
+ *
+ * // Inline trigger (drop-in for old API)
+ * attachProcessPicker(container, textarea);
*/
-import { fetchWithAuth } from './api.ts';
+import { fetchWithAuth, escapeHtml } from './api.ts';
import { t } from './i18n.ts';
-import { escapeHtml } from './api.ts';
+import { ICON_SEARCH } from './icons.ts';
-function renderList(picker: any, processes: string[], existing: Set): void {
- const listEl = picker.querySelector('.process-picker-list');
- if (processes.length === 0) {
- listEl.innerHTML = `${t('automations.condition.application.no_processes')}
`;
- return;
+/* ─── types ────────────────────────────────────────────────── */
+
+interface PaletteItem {
+ name: string;
+ added: boolean;
+}
+
+interface PickOpts {
+ current?: string;
+ placeholder?: string;
+}
+
+interface PickMultiOpts {
+ textarea: HTMLTextAreaElement;
+ placeholder?: string;
+}
+
+type FetchItemsFn = () => Promise;
+
+/* ─── generic NamePalette (shared logic) ───────────────────── */
+
+class NamePalette {
+ private _overlay: HTMLDivElement;
+ private _input: HTMLInputElement;
+ private _list: HTMLDivElement;
+ private _fetchItems: FetchItemsFn;
+
+ private _resolveSingle: ((v: string | undefined) => void) | null = null;
+ private _multiTextarea: HTMLTextAreaElement | null = null;
+
+ private _items: string[] = [];
+ private _existing: Set = new Set();
+ private _filtered: PaletteItem[] = [];
+ private _highlightIdx = 0;
+ private _currentValue: string | undefined;
+ private _isMulti = false;
+
+ constructor(fetchItems: FetchItemsFn) {
+ this._fetchItems = fetchItems;
+
+ this._overlay = document.createElement('div');
+ this._overlay.className = 'entity-palette-overlay process-palette-overlay';
+ this._overlay.innerHTML = `
+
+
+ ${ICON_SEARCH}
+
+
+
+
+ `;
+ document.body.appendChild(this._overlay);
+
+ this._input = this._overlay.querySelector('.entity-palette-input') as HTMLInputElement;
+ this._list = this._overlay.querySelector('.entity-palette-list') as HTMLDivElement;
+
+ this._overlay.addEventListener('click', (e) => {
+ if (e.target === this._overlay) this._close();
+ });
+ this._input.addEventListener('input', () => this._filter());
+ this._input.addEventListener('keydown', (e) => this._onKey(e));
}
- listEl.innerHTML = processes.map(p => {
- const added = existing.has(p.toLowerCase());
- return `${escapeHtml(p)}${added ? ' \u2713' : ''}
`;
- }).join('');
- listEl.querySelectorAll('.process-picker-item:not(.added)').forEach(item => {
- item.addEventListener('click', () => {
- const proc = item.dataset.process;
- const textarea = picker._textarea;
- const current = textarea.value.trim();
- textarea.value = current ? current + '\n' + proc : proc;
- item.classList.add('added');
- item.textContent = proc + ' \u2713';
- picker._existing.add(proc.toLowerCase());
+ /* ── open helpers ──────────────────────────────────────── */
+
+ pickSingle(opts: PickOpts): Promise {
+ return new Promise(resolve => {
+ this._isMulti = false;
+ this._multiTextarea = null;
+ this._resolveSingle = resolve;
+ this._currentValue = opts.current;
+ this._open(opts.placeholder);
+ });
+ }
+
+ pickMulti(opts: PickMultiOpts): Promise {
+ return new Promise(resolve => {
+ this._isMulti = true;
+ this._multiTextarea = opts.textarea;
+ this._resolveSingle = resolve as any;
+ this._existing = new Set(
+ opts.textarea.value.split('\n').map(s => s.trim().toLowerCase()).filter(Boolean),
+ );
+ this._currentValue = undefined;
+ this._open(opts.placeholder);
+ });
+ }
+
+ private async _open(placeholder?: string) {
+ this._input.placeholder = placeholder || '';
+ this._input.value = '';
+ this._list.innerHTML = `${t('common.loading')}
`;
+ this._overlay.classList.add('open');
+ requestAnimationFrame(() => this._input.focus());
+
+ try {
+ this._items = await this._fetchItems();
+ } catch {
+ this._items = [];
+ }
+
+ if (this._isMulti) {
+ this._existing = new Set(
+ this._multiTextarea!.value.split('\n').map(s => s.trim().toLowerCase()).filter(Boolean),
+ );
+ }
+
+ this._filter();
+ }
+
+ /* ── filtering & rendering ─────────────────────────────── */
+
+ private _filter() {
+ const q = this._input.value.toLowerCase().trim();
+ this._filtered = this._items
+ .filter(p => !q || p.toLowerCase().includes(q))
+ .map(p => ({
+ name: p,
+ added: this._existing.has(p.toLowerCase()),
+ }));
+
+ this._highlightIdx = this._filtered.findIndex(
+ i => i.name.toLowerCase() === (this._currentValue || '').toLowerCase(),
+ );
+ if (this._highlightIdx === -1) this._highlightIdx = 0;
+ this._render();
+ }
+
+ private _render() {
+ if (this._filtered.length === 0) {
+ this._list.innerHTML = `${
+ this._items.length === 0
+ ? t('automations.condition.application.no_processes')
+ : '—'
+ }
`;
+ return;
+ }
+
+ this._list.innerHTML = this._filtered.map((item, i) => {
+ const cls = [
+ 'entity-palette-item',
+ i === this._highlightIdx ? 'ep-highlight' : '',
+ item.added ? 'ep-current' : '',
+ item.name.toLowerCase() === (this._currentValue || '').toLowerCase() ? 'ep-current' : '',
+ ].filter(Boolean).join(' ');
+
+ return `
+ ${escapeHtml(item.name)}
+ ${item.added ? '\u2713' : ''}
+
`;
+ }).join('');
+
+ this._list.querySelectorAll('.entity-palette-item').forEach(el => {
+ el.addEventListener('click', () => {
+ const idx = parseInt((el as HTMLElement).dataset.idx!);
+ this._selectItem(this._filtered[idx]);
+ });
+ });
+
+ const hl = this._list.querySelector('.ep-highlight');
+ if (hl) hl.scrollIntoView({ block: 'nearest' });
+ }
+
+ /* ── selection ──────────────────────────────────────────── */
+
+ private _selectItem(item: PaletteItem) {
+ if (this._isMulti) {
+ if (!item.added) {
+ const ta = this._multiTextarea!;
+ const cur = ta.value.trim();
+ ta.value = cur ? cur + '\n' + item.name : item.name;
+ this._existing.add(item.name.toLowerCase());
+ item.added = true;
+ this._render();
+ }
+ } else {
+ this._overlay.classList.remove('open');
+ if (this._resolveSingle) this._resolveSingle(item.name);
+ this._resolveSingle = null;
+ }
+ }
+
+ private _close() {
+ this._overlay.classList.remove('open');
+ if (this._resolveSingle) this._resolveSingle(this._isMulti ? undefined as any : undefined);
+ this._resolveSingle = null;
+ }
+
+ /* ── keyboard ──────────────────────────────────────────── */
+
+ private _onKey(e: KeyboardEvent) {
+ if (e.key === 'ArrowDown') {
+ e.preventDefault();
+ this._highlightIdx = Math.min(this._highlightIdx + 1, this._filtered.length - 1);
+ this._render();
+ } else if (e.key === 'ArrowUp') {
+ e.preventDefault();
+ this._highlightIdx = Math.max(this._highlightIdx - 1, 0);
+ this._render();
+ } else if (e.key === 'Enter') {
+ e.preventDefault();
+ if (this._filtered[this._highlightIdx]) {
+ this._selectItem(this._filtered[this._highlightIdx]);
+ }
+ } else if (e.key === 'Escape') {
+ this._close();
+ } else if (e.key === 'Tab') {
+ e.preventDefault();
+ }
+ }
+}
+
+/* ─── fetch helpers ────────────────────────────────────────── */
+
+async function _fetchProcesses(): Promise {
+ const resp = await fetchWithAuth('/system/processes');
+ if (!resp || !resp.ok) return [];
+ const data = await resp.json();
+ return data.processes || [];
+}
+
+async function _fetchNotificationApps(): Promise {
+ const resp = await fetchWithAuth('/color-strip-sources/os-notifications/history');
+ if (!resp || !resp.ok) return [];
+ const data = await resp.json();
+ const history: any[] = data.history || [];
+ // Deduplicate app names, preserving original case of first occurrence
+ const seen = new Map();
+ for (const entry of history) {
+ const app = entry.app;
+ if (app && !seen.has(app.toLowerCase())) {
+ seen.set(app.toLowerCase(), app);
+ }
+ }
+ return Array.from(seen.values()).sort((a, b) => a.localeCompare(b));
+}
+
+/* ─── ProcessPalette (running processes) ───────────────────── */
+
+let _processInst: NamePalette | null = null;
+
+export class ProcessPalette {
+ static pick(opts: PickOpts): Promise {
+ if (!_processInst) _processInst = new NamePalette(_fetchProcesses);
+ return _processInst.pickSingle(opts);
+ }
+
+ static pickMulti(opts: PickMultiOpts): Promise {
+ if (!_processInst) _processInst = new NamePalette(_fetchProcesses);
+ return _processInst.pickMulti(opts);
+ }
+}
+
+/* ─── NotificationAppPalette (OS notification history) ─────── */
+
+let _notifInst: NamePalette | null = null;
+
+export class NotificationAppPalette {
+ static pick(opts: PickOpts): Promise {
+ if (!_notifInst) _notifInst = new NamePalette(_fetchNotificationApps);
+ return _notifInst.pickSingle(opts);
+ }
+
+ static pickMulti(opts: PickMultiOpts): Promise {
+ if (!_notifInst) _notifInst = new NamePalette(_fetchNotificationApps);
+ return _notifInst.pickMulti(opts);
+ }
+}
+
+/* ─── drop-in replacement for the old attachProcessPicker ─── */
+
+/**
+ * Wire up a `.btn-browse-apps` button inside `containerEl` to open the
+ * multi-select process palette feeding into `textareaEl`.
+ */
+export function attachProcessPicker(containerEl: HTMLElement, textareaEl: HTMLTextAreaElement): void {
+ const browseBtn = containerEl.querySelector('.btn-browse-apps');
+ if (!browseBtn) return;
+
+ browseBtn.addEventListener('click', () => {
+ ProcessPalette.pickMulti({
+ textarea: textareaEl,
+ placeholder: t('automations.condition.application.search') || 'Search processes…',
});
});
}
-async function toggle(picker: any): Promise {
- if (picker.style.display !== 'none') {
- picker.style.display = 'none';
- return;
- }
-
- const listEl = picker.querySelector('.process-picker-list');
- const searchEl = picker.querySelector('.process-picker-search');
- searchEl.value = '';
- listEl.innerHTML = `${t('common.loading')}
`;
- picker.style.display = '';
-
- try {
- const resp = await fetchWithAuth('/system/processes');
- if (!resp.ok) throw new Error('Failed to fetch processes');
- const data = await resp.json();
-
- const existing = new Set(
- (picker as any)._textarea.value.split('\n').map((a: string) => a.trim().toLowerCase()).filter(Boolean)
- );
-
- (picker as any)._processes = data.processes;
- (picker as any)._existing = existing;
- renderList(picker, data.processes, existing);
- searchEl.focus();
- } catch (e) {
- listEl.innerHTML = `${e.message}
`;
- }
-}
-
-function filter(picker: any): void {
- const query = picker.querySelector('.process-picker-search').value.toLowerCase();
- const filtered = (picker._processes || []).filter(p => p.includes(query));
- renderList(picker, filtered, picker._existing || new Set());
-}
-
/**
- * Wire up a process picker inside `containerEl` to feed into `textareaEl`.
- * containerEl must contain .btn-browse-apps, .process-picker, .process-picker-search.
+ * Wire up a `.btn-browse-apps` button to open the notification app palette
+ * (multi-select, feeding into a textarea).
*/
-export function attachProcessPicker(containerEl: HTMLElement, textareaEl: HTMLTextAreaElement): void {
+export function attachNotificationAppPicker(containerEl: HTMLElement, textareaEl: HTMLTextAreaElement): void {
const browseBtn = containerEl.querySelector('.btn-browse-apps');
- const picker = containerEl.querySelector('.process-picker');
- if (!browseBtn || !picker) return;
+ if (!browseBtn) return;
- (picker as any)._textarea = textareaEl;
- browseBtn.addEventListener('click', () => toggle(picker));
-
- const searchInput = picker.querySelector('.process-picker-search');
- if (searchInput) {
- searchInput.addEventListener('input', () => filter(picker));
- }
+ browseBtn.addEventListener('click', () => {
+ NotificationAppPalette.pickMulti({
+ textarea: textareaEl,
+ placeholder: t('color_strip.notification.search_apps') || 'Search notification apps…',
+ });
+ });
}
diff --git a/server/src/wled_controller/static/js/features/automations.ts b/server/src/wled_controller/static/js/features/automations.ts
index b875216..0b07065 100644
--- a/server/src/wled_controller/static/js/features/automations.ts
+++ b/server/src/wled_controller/static/js/features/automations.ts
@@ -507,6 +507,60 @@ function _buildConditionTypeItems() {
}));
}
+/** Wire up the custom time-range picker inputs → sync to hidden fields. */
+function _wireTimeRangePicker(container: HTMLElement) {
+ const startH = container.querySelector('.tr-start-h') as HTMLInputElement;
+ const startM = container.querySelector('.tr-start-m') as HTMLInputElement;
+ const endH = container.querySelector('.tr-end-h') as HTMLInputElement;
+ const endM = container.querySelector('.tr-end-m') as HTMLInputElement;
+ const hiddenStart = container.querySelector('.condition-start-time') as HTMLInputElement;
+ const hiddenEnd = container.querySelector('.condition-end-time') as HTMLInputElement;
+ if (!startH || !startM || !endH || !endM) return;
+
+ const pad = (n: number) => String(n).padStart(2, '0');
+
+ function clamp(input: HTMLInputElement, min: number, max: number) {
+ let v = parseInt(input.value, 10);
+ if (isNaN(v)) v = min;
+ if (v < min) v = min;
+ if (v > max) v = max;
+ input.value = pad(v);
+ return v;
+ }
+
+ function sync() {
+ const sh = clamp(startH, 0, 23);
+ const sm = clamp(startM, 0, 59);
+ const eh = clamp(endH, 0, 23);
+ const em = clamp(endM, 0, 59);
+ hiddenStart.value = `${pad(sh)}:${pad(sm)}`;
+ hiddenEnd.value = `${pad(eh)}:${pad(em)}`;
+ }
+
+ [startH, startM, endH, endM].forEach(inp => {
+ inp.addEventListener('focus', () => inp.select());
+ inp.addEventListener('input', sync);
+ inp.addEventListener('blur', sync);
+ inp.addEventListener('keydown', (e) => {
+ const isHour = inp.dataset.role === 'hour';
+ const max = isHour ? 23 : 59;
+ if (e.key === 'ArrowUp') {
+ e.preventDefault();
+ let v = parseInt(inp.value, 10) || 0;
+ inp.value = pad(v >= max ? 0 : v + 1);
+ sync();
+ } else if (e.key === 'ArrowDown') {
+ e.preventDefault();
+ let v = parseInt(inp.value, 10) || 0;
+ inp.value = pad(v <= 0 ? max : v - 1);
+ sync();
+ }
+ });
+ });
+
+ sync();
+}
+
function addAutomationConditionRow(condition: any) {
const list = document.getElementById('automation-conditions-list');
const row = document.createElement('div');
@@ -545,18 +599,35 @@ function addAutomationConditionRow(condition: any) {
if (type === 'time_of_day') {
const startTime = data.start_time || '00:00';
const endTime = data.end_time || '23:59';
+ const [sh, sm] = startTime.split(':').map(Number);
+ const [eh, em] = endTime.split(':').map(Number);
+ const pad = (n: number) => String(n).padStart(2, '0');
container.innerHTML = `
-
-
-
-
-
-
-
+
+
+
${t('automations.condition.time_of_day.overnight_hint')}
`;
+ _wireTimeRangePicker(container);
return;
}
if (type === 'system_idle') {
@@ -660,10 +731,6 @@ function addAutomationConditionRow(condition: any) {
-
`;
diff --git a/server/src/wled_controller/static/js/features/color-strips.ts b/server/src/wled_controller/static/js/features/color-strips.ts
index 642c478..18e7a6e 100644
--- a/server/src/wled_controller/static/js/features/color-strips.ts
+++ b/server/src/wled_controller/static/js/features/color-strips.ts
@@ -14,13 +14,13 @@ import {
ICON_LED, ICON_PALETTE, ICON_FPS, ICON_MAP_PIN, ICON_MUSIC,
ICON_AUDIO_LOOPBACK, ICON_TIMER, ICON_LINK_SOURCE, ICON_FILM,
ICON_LINK, ICON_SPARKLES, ICON_ACTIVITY, ICON_CLOCK, ICON_BELL, ICON_TEST,
- ICON_SUN_DIM, ICON_WARNING, ICON_AUTOMATION,
+ ICON_SUN_DIM, ICON_WARNING, ICON_AUTOMATION, ICON_SEARCH,
} from '../core/icons.ts';
import * as P from '../core/icon-paths.ts';
import { wrapCard } from '../core/card-colors.ts';
import type { ColorStripSource } from '../types.ts';
import { TagInput, renderTagChips } from '../core/tag-input.ts';
-import { attachProcessPicker } from '../core/process-picker.ts';
+import { attachNotificationAppPicker, NotificationAppPalette } from '../core/process-picker.ts';
import { IconSelect, showTypePicker } from '../core/icon-select.ts';
import { EntitySelect } from '../core/entity-palette.ts';
import { getBaseOrigin } from './settings.ts';
@@ -1270,11 +1270,30 @@ function _notificationAppColorsRenderList() {
list.innerHTML = _notificationAppColors.map((entry, i) => `
+
-
`).join('');
+
+ // Wire up browse buttons to open process palette
+ list.querySelectorAll('.notif-app-browse').forEach(btn => {
+ btn.addEventListener('click', async () => {
+ const idx = parseInt(btn.dataset.idx!);
+ const nameInput = list.querySelector(`.notif-app-name[data-idx="${idx}"]`);
+ if (!nameInput) return;
+ const picked = await NotificationAppPalette.pick({
+ current: nameInput.value,
+ placeholder: t('color_strip.notification.search_apps') || 'Search notification apps…',
+ });
+ if (picked !== undefined) {
+ nameInput.value = picked;
+ _notificationAppColorsSyncFromDom();
+ }
+ });
+ });
}
export function notificationAddAppColor() {
@@ -1443,7 +1462,7 @@ function _resetNotificationState() {
function _attachNotificationProcessPicker() {
const container = document.getElementById('css-editor-notification-filter-picker-container') as HTMLElement | null;
const textarea = document.getElementById('css-editor-notification-filter-list') as HTMLTextAreaElement | null;
- if (container && textarea) attachProcessPicker(container, textarea);
+ if (container && textarea) attachNotificationAppPicker(container, textarea);
}
function _showNotificationEndpoint(cssId: any) {
diff --git a/server/src/wled_controller/static/locales/en.json b/server/src/wled_controller/static/locales/en.json
index ea60218..1de91fd 100644
--- a/server/src/wled_controller/static/locales/en.json
+++ b/server/src/wled_controller/static/locales/en.json
@@ -1,1747 +1,1748 @@
{
- "app.title": "LED Grab",
- "app.version": "Version:",
- "app.api_docs": "API Documentation",
- "app.connection_lost": "Server unreachable",
- "app.connection_retrying": "Attempting to reconnect…",
- "demo.badge": "DEMO",
- "demo.banner": "You're in demo mode — all devices and data are virtual. No real hardware is used.",
- "theme.toggle": "Toggle theme",
- "bg.anim.toggle": "Toggle ambient background",
- "accent.title": "Accent color",
- "accent.custom": "Custom",
- "accent.reset": "Reset",
- "locale.change": "Change language",
- "auth.login": "Login",
- "auth.logout": "Logout",
- "auth.authenticated": "● Authenticated",
- "auth.title": "Login to LED Grab",
- "auth.message": "Please enter your API key to authenticate and access the LED Grab.",
- "auth.label": "API Key:",
- "auth.placeholder": "Enter your API key...",
- "auth.hint": "Your API key will be stored securely in your browser's local storage.",
- "auth.button.cancel": "Cancel",
- "auth.button.login": "Login",
- "auth.error.required": "Please enter an API key",
- "auth.success": "Logged in successfully!",
- "auth.logout.confirm": "Are you sure you want to logout?",
- "auth.logout.success": "Logged out successfully",
- "auth.please_login": "Please login to view",
- "auth.session_expired": "Your session has expired or the API key is invalid. Please login again.",
- "auth.prompt_update": "Current API key is set. Enter new key to update or leave blank to remove:",
- "auth.prompt_enter": "Enter your API key:",
- "auth.toggle_password": "Toggle password visibility",
- "api_key.login": "Login",
- "displays.title": "Available Displays",
- "displays.layout": "Displays",
- "displays.information": "Display Information",
- "displays.legend.primary": "Primary Display",
- "displays.legend.secondary": "Secondary Display",
- "displays.badge.primary": "Primary",
- "displays.badge.secondary": "Secondary",
- "displays.resolution": "Resolution:",
- "displays.refresh_rate": "Refresh Rate:",
- "displays.position": "Position:",
- "displays.index": "Display Index:",
- "displays.loading": "Loading displays...",
- "displays.none": "No displays available",
- "displays.failed": "Failed to load displays",
- "displays.picker.title": "Select a Display",
- "displays.picker.title.device": "Select a Device",
- "displays.picker.select": "Select display...",
- "displays.picker.click_to_select": "Click to select this display",
- "displays.picker.adb_connect": "Connect ADB device",
- "displays.picker.adb_connect.placeholder": "IP address (e.g. 192.168.2.201)",
- "displays.picker.adb_connect.button": "Connect",
- "displays.picker.adb_connect.success": "Device connected",
- "displays.picker.adb_connect.error": "Failed to connect device",
- "displays.picker.adb_disconnect": "Disconnect",
- "displays.picker.no_android": "No Android devices found. Connect via USB or enter IP above.",
- "templates.title": "Engine Templates",
- "templates.description": "Capture templates define how the screen is captured. Each template uses a specific capture engine (MSS, DXcam, WGC) with custom settings. Assign templates to devices for optimal performance.",
- "templates.loading": "Loading templates...",
- "templates.empty": "No capture templates configured",
- "templates.add": "Add Engine Template",
- "templates.edit": "Edit Engine Template",
- "templates.name": "Template Name:",
- "templates.name.placeholder": "My Custom Template",
- "templates.description.label": "Description (optional):",
- "templates.description.placeholder": "Describe this template...",
- "templates.engine": "Capture Engine:",
- "templates.engine.hint": "Select the screen capture technology to use",
- "templates.engine.select": "Select an engine...",
- "templates.engine.unavailable": "Unavailable",
- "templates.engine.unavailable.hint": "This engine is not available on your system",
- "templates.engine.mss.desc": "Cross-platform, pure Python",
- "templates.engine.dxcam.desc": "DirectX, low latency",
- "templates.engine.bettercam.desc": "DirectX, high performance",
- "templates.engine.camera.desc": "USB/IP camera capture",
- "templates.engine.scrcpy.desc": "Android screen mirror",
- "templates.engine.wgc.desc": "Windows Graphics Capture",
- "templates.config": "Configuration",
- "templates.config.show": "Show configuration",
- "templates.config.none": "No additional configuration",
- "templates.config.default": "Default",
- "templates.config.camera_backend.auto": "Auto-detect best backend",
- "templates.config.camera_backend.dshow": "Windows DirectShow",
- "templates.config.camera_backend.msmf": "Windows Media Foundation",
- "templates.config.camera_backend.v4l2": "Linux Video4Linux2",
- "templates.created": "Template created successfully",
- "templates.updated": "Template updated successfully",
- "templates.deleted": "Template deleted successfully",
- "templates.delete.confirm": "Are you sure you want to delete this template?",
- "templates.error.load": "Failed to load templates",
- "templates.error.engines": "Failed to load engines",
- "templates.error.required": "Please fill in all required fields",
- "templates.error.delete": "Failed to delete template",
- "templates.test.title": "Test Capture",
- "templates.test.description": "Test this template before saving to see a capture preview and performance metrics.",
- "templates.test.display": "Display:",
- "templates.test.display.select": "Select display...",
- "templates.test.duration": "Capture Duration (s):",
- "templates.test.border_width": "Border Width (px):",
- "templates.test.run": "Run",
- "templates.test.running": "Running test...",
- "templates.test.results.preview": "Full Capture Preview",
- "templates.test.results.borders": "Border Extraction",
- "templates.test.results.top": "Top",
- "templates.test.results.right": "Right",
- "templates.test.results.bottom": "Bottom",
- "templates.test.results.left": "Left",
- "templates.test.results.performance": "Performance",
- "templates.test.results.capture_time": "Capture",
- "templates.test.results.extraction_time": "Extraction",
- "templates.test.results.total_time": "Total",
- "templates.test.results.max_fps": "Max FPS",
- "templates.test.results.duration": "Duration",
- "templates.test.results.frame_count": "Frames",
- "templates.test.results.actual_fps": "Actual FPS",
- "templates.test.results.avg_capture_time": "Avg Capture",
- "templates.test.results.resolution": "Resolution:",
- "templates.test.error.no_engine": "Please select a capture engine",
- "templates.test.error.no_display": "Please select a display",
- "templates.test.error.failed": "Test failed",
- "devices.title": "Devices",
- "device.select_type": "Select Device Type",
- "devices.add": "Add New Device",
- "devices.loading": "Loading devices...",
- "devices.none": "No devices configured",
- "devices.failed": "Failed to load devices",
- "devices.wled_config": "WLED Configuration:",
- "devices.wled_note": "Configure your WLED device (effects, segments, color order, power limits, etc.) using the",
- "devices.wled_link": "official WLED app",
- "devices.wled_note_or": "or the built-in",
- "devices.wled_webui_link": "WLED Web UI",
- "devices.wled_note_webui": "(open your device's IP in a browser).",
- "devices.wled_note2": "This controller sends pixel color data and controls brightness per device.",
- "device.scan": "Auto Discovery",
- "device.scan.empty": "No devices found",
- "device.scan.error": "Network scan failed",
- "device.scan.already_added": "Already added",
- "device.scan.selected": "Device selected",
- "device.type": "Device Type:",
- "device.type.hint": "Select the type of LED controller",
- "device.type.wled": "WLED",
- "device.type.wled.desc": "WiFi LED controller over HTTP/UDP",
- "device.type.adalight": "Adalight",
- "device.type.adalight.desc": "Serial LED protocol for Arduino",
- "device.type.ambiled": "AmbiLED",
- "device.type.ambiled.desc": "Serial protocol for AmbiLED devices",
- "device.type.mqtt": "MQTT",
- "device.type.mqtt.desc": "Publish LED data via MQTT broker",
- "device.type.ws": "WebSocket",
- "device.type.ws.desc": "Stream LED data to WebSocket clients",
- "device.type.openrgb": "OpenRGB",
- "device.type.openrgb.desc": "Control RGB peripherals via OpenRGB",
- "device.type.dmx": "DMX",
- "device.type.dmx.desc": "Art-Net / sACN (E1.31) stage lighting",
- "device.type.mock": "Mock",
- "device.type.mock.desc": "Virtual device for testing",
- "device.type.espnow": "ESP-NOW",
- "device.type.espnow.desc": "Ultra-low-latency via ESP32 gateway",
- "device.type.hue": "Philips Hue",
- "device.type.hue.desc": "Hue Entertainment API streaming",
- "device.type.usbhid": "USB HID",
- "device.type.usbhid.desc": "USB RGB peripherals (keyboards, mice)",
- "device.type.spi": "SPI Direct",
- "device.type.spi.desc": "Raspberry Pi GPIO/SPI LED strips",
- "device.type.chroma": "Razer Chroma",
- "device.type.chroma.desc": "Razer peripherals via Chroma SDK",
- "device.type.gamesense": "SteelSeries",
- "device.type.gamesense.desc": "SteelSeries peripherals via GameSense",
- "device.chroma.device_type": "Peripheral Type:",
- "device.chroma.device_type.hint": "Which Razer peripheral to control via Chroma SDK",
- "device.gamesense.device_type": "Peripheral Type:",
- "device.gamesense.device_type.hint": "Which SteelSeries peripheral to control via GameSense",
- "device.espnow.peer_mac": "Peer MAC:",
- "device.espnow.peer_mac.hint": "MAC address of the remote ESP32 receiver (e.g. AA:BB:CC:DD:EE:FF)",
- "device.espnow.channel": "WiFi Channel:",
- "device.espnow.channel.hint": "WiFi channel (1-14). Must match the receiver's channel.",
- "device.hue.url": "Bridge IP:",
- "device.hue.url.hint": "IP address of your Hue bridge",
- "device.hue.username": "Bridge Username:",
- "device.hue.username.hint": "Hue bridge application key from pairing",
- "device.hue.client_key": "Client Key:",
- "device.hue.client_key.hint": "Entertainment API client key (hex string from pairing)",
- "device.hue.group_id": "Entertainment Group:",
- "device.hue.group_id.hint": "Entertainment configuration ID from your Hue bridge",
- "device.usbhid.url": "VID:PID:",
- "device.usbhid.url.hint": "USB Vendor:Product ID in hex (e.g. 1532:0084)",
- "device.spi.url": "GPIO/SPI Path:",
- "device.spi.url.hint": "GPIO pin or SPI device path (e.g. spi://gpio:18)",
- "device.spi.speed": "SPI Speed (Hz):",
- "device.spi.speed.hint": "SPI clock speed. 800000 Hz for WS2812, 2400000 Hz for APA102.",
- "device.spi.led_type": "LED Chipset:",
- "device.spi.led_type.hint": "Type of addressable LED strip connected to the GPIO/SPI pin",
- "device.spi.led_type.ws2812b.desc": "Most common, 800 KHz data, 3-wire RGB",
- "device.spi.led_type.ws2812.desc": "Original WS2812, 800 KHz, 3-wire RGB",
- "device.spi.led_type.ws2811.desc": "External driver IC, 400 KHz, 12V strips",
- "device.spi.led_type.sk6812.desc": "Samsung LED, 800 KHz, 3-wire RGB",
- "device.spi.led_type.sk6812_rgbw.desc": "SK6812 with dedicated white channel",
- "device.gamesense.peripheral.keyboard": "Keyboard",
- "device.gamesense.peripheral.keyboard.desc": "Per-key RGB illumination",
- "device.gamesense.peripheral.mouse": "Mouse",
- "device.gamesense.peripheral.mouse.desc": "Mouse RGB zones",
- "device.gamesense.peripheral.headset": "Headset",
- "device.gamesense.peripheral.headset.desc": "Headset earcup lighting",
- "device.gamesense.peripheral.mousepad": "Mousepad",
- "device.gamesense.peripheral.mousepad.desc": "Mousepad edge lighting zones",
- "device.gamesense.peripheral.indicator": "Indicator",
- "device.gamesense.peripheral.indicator.desc": "OLED/LED status indicator",
- "device.css_processing_template": "Strip Processing Template:",
- "device.css_processing_template.hint": "Default processing template applied to all color strip outputs on this device",
- "device.dmx_protocol": "DMX Protocol:",
- "device.dmx_protocol.hint": "Art-Net uses UDP port 6454, sACN (E1.31) uses UDP port 5568",
- "device.dmx_protocol.artnet.desc": "UDP unicast, port 6454",
- "device.dmx_protocol.sacn.desc": "Multicast/unicast, port 5568",
- "device.dmx_start_universe": "Start Universe:",
- "device.dmx_start_universe.hint": "First DMX universe (0-32767). Multiple universes are used automatically for >170 LEDs.",
- "device.dmx_start_channel": "Start Channel:",
- "device.dmx_start_channel.hint": "First DMX channel within the universe (1-512)",
- "device.dmx.url": "IP Address:",
- "device.dmx.url.hint": "IP address of the DMX node (e.g. 192.168.1.50)",
- "device.dmx.url.placeholder": "192.168.1.50",
- "device.serial_port": "Serial Port:",
- "device.serial_port.hint": "Select the COM port of the Adalight device",
- "device.serial_port.none": "No serial ports found",
- "device.serial_port.select": "Select a port...",
- "device.led_count_manual.hint": "Number of LEDs on the strip (must match your Arduino sketch)",
- "device.baud_rate": "Baud Rate:",
- "device.baud_rate.hint": "Serial communication speed. Higher = more FPS but requires matching Arduino sketch.",
- "device.led_type": "LED Type:",
- "device.led_type.hint": "RGB (3 channels) or RGBW (4 channels with dedicated white)",
- "device.send_latency": "Send Latency (ms):",
- "device.send_latency.hint": "Simulated network/serial delay per frame in milliseconds",
- "device.mqtt_topic": "MQTT Topic:",
- "device.mqtt_topic.hint": "MQTT topic path for publishing pixel data (e.g. mqtt://ledgrab/device/name)",
- "device.mqtt_topic.placeholder": "mqtt://ledgrab/device/living-room",
- "device.ws_url": "Connection URL:",
- "device.ws_url.hint": "WebSocket URL for clients to connect and receive LED data",
- "device.openrgb.url": "OpenRGB URL:",
- "device.openrgb.url.hint": "OpenRGB server address (e.g. openrgb://localhost:6742/0)",
- "device.openrgb.zone": "Zones:",
- "device.openrgb.zone.hint": "Select which LED zones to control (leave all unchecked for all zones)",
- "device.openrgb.zone.loading": "Loading zones…",
- "device.openrgb.zone.error": "Failed to load zones",
- "device.openrgb.mode": "Zone mode:",
- "device.openrgb.mode.hint": "Combined treats all zones as one continuous LED strip. Separate renders each zone independently with the full effect.",
- "device.openrgb.mode.combined": "Combined strip",
- "device.openrgb.mode.separate": "Independent zones",
- "device.openrgb.added_multiple": "Added {count} devices",
- "device.type.openrgb": "OpenRGB",
- "device.url.hint": "IP address or hostname of the device (e.g. http://192.168.1.100)",
- "device.name": "Device Name:",
- "device.name.placeholder": "Living Room TV",
- "device.url": "URL:",
- "device.url.placeholder": "http://192.168.1.100",
- "device.led_count": "LED Count:",
- "device.led_count.hint": "Number of LEDs configured in the device",
- "device.led_count.hint.auto": "Auto-detected from device",
- "device.button.add": "Add Device",
- "device.button.start": "Start",
- "device.button.stop": "Stop",
- "device.button.settings": "General Settings",
- "device.button.capture_settings": "Capture Settings",
- "device.button.calibrate": "Calibrate",
- "device.button.remove": "Remove",
- "device.button.webui": "Open Device Web UI",
- "device.button.power_off": "Turn Off",
- "device.button.ping": "Ping Device",
- "device.ping.online": "Online ({ms}ms)",
- "device.ping.offline": "Device offline",
- "device.ping.error": "Ping failed",
- "device.power.off_success": "Device turned off",
- "device.status.connected": "Connected",
- "device.status.disconnected": "Disconnected",
- "device.status.error": "Error",
- "device.status.processing": "Processing",
- "device.status.idle": "Idle",
- "device.fps": "FPS:",
- "device.display": "Display:",
- "device.remove.confirm": "Are you sure you want to remove this device?",
- "device.added": "Device added successfully",
- "device.removed": "Device removed successfully",
- "device.started": "Processing started",
- "device.stopped": "Processing stopped",
- "device.metrics.actual_fps": "Actual FPS",
- "device.metrics.current_fps": "Current FPS",
- "device.metrics.target_fps": "Target FPS",
- "device.metrics.potential_fps": "Potential FPS",
- "device.metrics.frames": "Frames",
- "device.metrics.frames_skipped": "Skipped",
- "device.metrics.keepalive": "Keepalive",
- "device.metrics.errors": "Errors",
- "device.metrics.uptime": "Uptime",
- "device.metrics.timing": "Pipeline timing:",
- "device.metrics.device_fps": "Device refresh rate",
- "device.health.online": "Online",
- "device.health.offline": "Offline",
- "device.health.streaming_unreachable": "Unreachable during streaming",
- "device.health.checking": "Checking...",
- "device.last_seen.label": "Last seen",
- "device.last_seen.just_now": "just now",
- "device.last_seen.seconds": "%ds ago",
- "device.last_seen.minutes": "%dm ago",
- "device.last_seen.hours": "%dh ago",
- "device.last_seen.days": "%dd ago",
- "device.tutorial.start": "Start tutorial",
- "device.tip.metadata": "Device info (LED count, type, color channels) is auto-detected from the device",
- "device.tip.brightness": "Slide to adjust device brightness",
- "device.tip.start": "Start or stop screen capture processing",
- "device.tip.settings": "Configure general device settings (name, URL, health check)",
- "device.tip.capture_settings": "Configure capture settings (display, capture template)",
- "device.tip.calibrate": "Calibrate LED positions, direction, and coverage",
- "device.tip.webui": "Open the device's built-in web interface for advanced configuration",
- "device.tip.add": "Click here to add a new LED device",
- "settings.title": "Settings",
- "settings.tab.general": "General",
- "settings.tab.backup": "Backup",
- "settings.tab.mqtt": "MQTT",
- "settings.logs.open_viewer": "Open Log Viewer",
- "settings.external_url.label": "External URL",
- "settings.external_url.hint": "If set, this base URL is used in webhook URLs and other user-visible links instead of the auto-detected local IP. Example: https://myserver.example.com:8080",
- "settings.external_url.placeholder": "https://myserver.example.com:8080",
- "settings.external_url.save": "Save",
- "settings.external_url.saved": "External URL saved",
- "settings.external_url.save_error": "Failed to save external URL",
- "settings.general.title": "General Settings",
- "settings.capture.title": "Capture Settings",
- "settings.capture.saved": "Capture settings updated",
- "settings.capture.failed": "Failed to save capture settings",
- "settings.brightness": "Brightness:",
- "settings.brightness.hint": "Global brightness for this device (0-100%)",
- "settings.url.hint": "IP address or hostname of the device",
- "settings.display_index": "Display:",
- "settings.display_index.hint": "Which screen to capture for this device",
- "settings.fps": "Target FPS:",
- "settings.fps.hint": "Target frames per second (10-90)",
- "settings.capture_template": "Engine Template:",
- "settings.capture_template.hint": "Screen capture engine and configuration for this device",
- "settings.button.cancel": "Cancel",
- "settings.health_interval": "Health Check Interval (s):",
- "settings.health_interval.hint": "How often to check the device status (5-600 seconds)",
- "settings.auto_shutdown": "Auto Restore:",
- "settings.auto_shutdown.hint": "Restore device to idle state when targets stop or server shuts down",
- "settings.button.save": "Save Changes",
- "settings.saved": "Settings saved successfully",
- "settings.failed": "Failed to save settings",
- "calibration.title": "LED Calibration",
- "calibration.tip.led_count": "Enter LED count per edge",
- "calibration.tip.start_corner": "Click a corner to set the start position",
- "calibration.tip.direction": "Toggle LED strip direction (clockwise / counterclockwise)",
- "calibration.tip.offset": "Set LED offset — distance from LED 0 to the start corner",
- "calibration.tip.span": "Drag green bars to adjust coverage span",
- "calibration.tip.test": "Click an edge to toggle test LEDs",
- "calibration.tip.overlay": "Toggle screen overlay to see LED positions and numbering on your monitor",
- "calibration.tip.toggle_inputs": "Click total LED count to toggle edge inputs",
- "calibration.tip.border_width": "How many pixels from the screen edge to sample for LED colors",
- "calibration.tip.skip_leds_start": "Skip LEDs at the start of the strip — skipped LEDs stay off",
- "calibration.tip.skip_leds_end": "Skip LEDs at the end of the strip — skipped LEDs stay off",
- "tour.welcome": "Welcome to LED Grab! This quick tour will show you around the interface. Use arrow keys or buttons to navigate.",
- "tour.dashboard": "Dashboard — live overview of running targets, automations, and device health at a glance.",
- "tour.targets": "Targets — add WLED devices, configure LED targets with capture settings and calibration.",
- "tour.sources": "Sources — manage capture templates, picture sources, audio sources, and color strips.",
- "tour.graph": "Graph — visual overview of all entities and their connections. Drag ports to connect, right-click edges to disconnect.",
- "tour.automations": "Automations — automate scene switching with time, audio, or value conditions.",
- "tour.settings": "Settings — backup and restore configuration, manage auto-backups.",
- "tour.api": "API Docs — interactive REST API documentation powered by Swagger.",
- "tour.search": "Search — quickly find and navigate to any entity with Ctrl+K.",
- "tour.theme": "Theme — switch between dark and light mode.",
- "tour.accent": "Accent color — customize the UI accent color to your preference.",
- "tour.language": "Language — choose your preferred interface language.",
- "tour.restart": "Restart tutorial",
- "tour.dash.perf": "Performance — real-time FPS charts, latency metrics, and poll interval control.",
- "tour.dash.running": "Running targets — live streaming metrics and quick stop control.",
- "tour.dash.stopped": "Stopped targets — ready to start with one click.",
- "tour.dash.automations": "Automations — active automation status and quick enable/disable toggle.",
- "tour.tgt.led_tab": "LED tab — standard LED strip targets with device and color strip configuration.",
- "tour.tgt.devices": "Devices — your LED controllers discovered on the network.",
- "tour.tgt.css": "Color Strips — define how screen regions map to LED segments.",
- "tour.tgt.targets": "LED Targets — combine a device, color strip, and capture source for streaming.",
- "tour.tgt.kc_tab": "Key Colors — alternative target type using color-matching instead of pixel mapping.",
- "tour.src.raw": "Raw — live screen capture sources from your displays.",
- "tour.src.templates": "Capture Templates — reusable capture configurations (resolution, FPS, crop).",
- "tour.src.static": "Static Image — test your setup with image files instead of live capture.",
- "tour.src.processed": "Processed — apply post-processing effects like blur, brightness, or color correction.",
- "tour.src.color_strip": "Color Strips — define how screen regions map to LED segments.",
- "tour.src.audio": "Audio — analyze microphone or system audio for reactive LED effects.",
- "tour.src.value": "Value — numeric data sources used as conditions in automations.",
- "tour.src.sync": "Sync Clocks — shared timers that synchronize animations across multiple sources.",
- "tour.auto.list": "Automations — automate scene activation based on time, audio, or value conditions.",
- "tour.auto.add": "Click + to create a new automation with conditions and a scene to activate.",
- "tour.auto.card": "Each card shows automation status, conditions, and quick controls to edit or toggle.",
- "tour.auto.scenes_list": "Scenes — saved system states that automations can activate or you can apply manually.",
- "tour.auto.scenes_add": "Click + to capture the current system state as a new scene preset.",
- "tour.auto.scenes_card": "Each scene card shows target/device counts. Click to edit, recapture, or activate.",
- "calibration.tutorial.start": "Start tutorial",
- "calibration.overlay_toggle": "Overlay",
- "calibration.start_position": "Starting Position:",
- "calibration.position.bottom_left": "Bottom Left",
- "calibration.position.bottom_right": "Bottom Right",
- "calibration.position.top_left": "Top Left",
- "calibration.position.top_right": "Top Right",
- "calibration.direction": "Direction:",
- "calibration.direction.clockwise": "Clockwise",
- "calibration.direction.counterclockwise": "Counterclockwise",
- "calibration.leds.top": "Top LEDs:",
- "calibration.leds.right": "Right LEDs:",
- "calibration.leds.bottom": "Bottom LEDs:",
- "calibration.leds.left": "Left LEDs:",
- "calibration.offset": "LED Offset:",
- "calibration.offset.hint": "Distance from physical LED 0 to the start corner (along strip direction)",
- "calibration.skip_start": "Skip LEDs (Start):",
- "calibration.skip_start.hint": "Number of LEDs to turn off at the beginning of the strip (0 = none)",
- "calibration.skip_end": "Skip LEDs (End):",
- "calibration.skip_end.hint": "Number of LEDs to turn off at the end of the strip (0 = none)",
- "calibration.border_width": "Border (px):",
- "calibration.border_width.hint": "How many pixels from the screen edge to sample for LED colors (1-100)",
- "calibration.button.cancel": "Cancel",
- "calibration.button.save": "Save",
- "calibration.saved": "Calibration saved successfully",
- "calibration.failed": "Failed to save calibration",
- "server.healthy": "Server online",
- "server.offline": "Server offline",
- "error.unauthorized": "Unauthorized - please login",
- "error.network": "Network error",
- "error.unknown": "An error occurred",
- "modal.discard_changes": "You have unsaved changes. Discard them?",
- "confirm.title": "Confirm Action",
- "confirm.yes": "Yes",
- "confirm.no": "No",
- "confirm.stop_all": "Stop all running targets?",
- "confirm.turn_off_device": "Turn off this device?",
- "common.loading": "Loading...",
- "common.delete": "Delete",
- "common.edit": "Edit",
- "common.clone": "Clone",
- "common.none": "None",
- "common.none_no_cspt": "None (no processing template)",
- "common.none_no_input": "None (no input source)",
- "common.none_own_speed": "None (use own speed)",
- "common.undo": "Undo",
- "validation.required": "This field is required",
- "bulk.processing": "Processing…",
- "api.error.timeout": "Request timed out — please try again",
- "api.error.network": "Network error — check your connection",
- "palette.search": "Search…",
- "section.filter.placeholder": "Filter...",
- "section.filter.reset": "Clear filter",
- "tags.label": "Tags",
- "tags.hint": "Assign tags for grouping and filtering cards",
- "tags.placeholder": "Add tag...",
- "section.expand_all": "Expand all sections",
- "section.collapse_all": "Collapse all sections",
- "streams.title": "Sources",
- "streams.description": "Sources define the capture pipeline. A raw source captures from a display using a capture template. A processed source applies postprocessing to another source. Assign sources to devices.",
- "streams.group.raw": "Sources",
- "streams.group.raw_templates": "Engine Templates",
- "streams.group.processed": "Sources",
- "streams.group.proc_templates": "Filter Templates",
- "streams.group.css_processing": "Processing Templates",
- "streams.group.color_strip": "Color Strips",
- "streams.group.audio": "Audio",
- "streams.group.audio_templates": "Audio Templates",
- "streams.section.streams": "Sources",
- "streams.add": "Add Source",
- "streams.add.raw": "Add Screen Capture",
- "streams.add.processed": "Add Processed Source",
- "streams.edit": "Edit Source",
- "streams.edit.raw": "Edit Screen Capture",
- "streams.edit.processed": "Edit Processed Source",
- "streams.name": "Source Name:",
- "streams.name.placeholder": "My Source",
- "streams.type": "Type:",
- "streams.type.raw": "Screen Capture",
- "streams.type.processed": "Processed",
- "streams.display": "Display:",
- "streams.display.hint": "Which screen to capture",
- "streams.capture_template": "Engine Template:",
- "streams.capture_template.hint": "Engine template defining how the screen is captured",
- "streams.target_fps": "Target FPS:",
- "streams.target_fps.hint": "Target frames per second for capture (1-90)",
- "streams.source": "Source:",
- "streams.source.hint": "The source to apply processing filters to",
- "streams.pp_template": "Filter Template:",
- "streams.pp_template.hint": "Filter template to apply to the source",
- "streams.description_label": "Description (optional):",
- "streams.description_placeholder": "Describe this source...",
- "streams.created": "Source created successfully",
- "streams.updated": "Source updated successfully",
- "streams.deleted": "Source deleted successfully",
- "streams.delete.confirm": "Are you sure you want to delete this source?",
- "streams.modal.loading": "Loading...",
- "streams.error.load": "Failed to load sources",
- "streams.error.required": "Please fill in all required fields",
- "streams.error.delete": "Failed to delete source",
- "streams.test.title": "Test Source",
- "streams.test.run": "Run",
- "streams.test.running": "Testing source...",
- "streams.test.duration": "Capture Duration (s):",
- "streams.test.error.failed": "Source test failed",
- "postprocessing.title": "Filter Templates",
- "postprocessing.description": "Processing templates define image filters and color correction. Assign them to processed picture sources for consistent postprocessing across devices.",
- "postprocessing.add": "Add Filter Template",
- "postprocessing.edit": "Edit Filter Template",
- "postprocessing.name": "Template Name:",
- "postprocessing.name.placeholder": "My Filter Template",
- "filters.select_type": "Select filter type...",
- "filters.add": "Add Filter",
- "filters.remove": "Remove",
- "filters.drag_to_reorder": "Drag to reorder",
- "filters.empty": "No filters added. Use the selector below to add filters.",
- "filters.brightness": "Brightness",
- "filters.brightness.desc": "Adjust overall image brightness",
- "filters.saturation": "Saturation",
- "filters.saturation.desc": "Boost or reduce color intensity",
- "filters.gamma": "Gamma",
- "filters.gamma.desc": "Non-linear brightness curve correction",
- "filters.downscaler": "Downscaler",
- "filters.downscaler.desc": "Reduce resolution for faster processing",
- "filters.pixelate": "Pixelate",
- "filters.pixelate.desc": "Mosaic-style block averaging",
- "filters.auto_crop": "Auto Crop",
- "filters.auto_crop.desc": "Remove black bars from letterboxed content",
- "filters.flip": "Flip",
- "filters.flip.desc": "Mirror image horizontally or vertically",
- "filters.color_correction": "Color Correction",
- "filters.color_correction.desc": "White balance and color temperature",
- "filters.filter_template": "Filter Template",
- "filters.filter_template.desc": "Embed another processing template",
- "filters.css_filter_template": "Strip Filter Template",
- "filters.css_filter_template.desc": "Embed another strip processing template",
- "filters.frame_interpolation": "Frame Interpolation",
- "filters.frame_interpolation.desc": "Blend between frames for smoother output",
- "filters.noise_gate": "Noise Gate",
- "filters.noise_gate.desc": "Suppress small color changes below threshold",
- "filters.palette_quantization": "Palette Quantization",
- "filters.palette_quantization.desc": "Reduce colors to a limited palette",
- "filters.reverse": "Reverse",
- "filters.reverse.desc": "Reverse the LED order in the strip",
- "postprocessing.description_label": "Description (optional):",
- "postprocessing.description_placeholder": "Describe this template...",
- "postprocessing.created": "Template created successfully",
- "postprocessing.updated": "Template updated successfully",
- "postprocessing.deleted": "Template deleted successfully",
- "postprocessing.delete.confirm": "Are you sure you want to delete this filter template?",
- "postprocessing.error.load": "Failed to load processing templates",
- "postprocessing.error.required": "Please fill in all required fields",
- "postprocessing.error.delete": "Failed to delete processing template",
- "postprocessing.config.show": "Show settings",
- "postprocessing.test.title": "Test Filter Template",
- "postprocessing.test.source_stream": "Source:",
- "postprocessing.test.running": "Testing processing template...",
- "postprocessing.test.error.no_stream": "Please select a source",
- "postprocessing.test.error.failed": "Processing template test failed",
- "css_processing.title": "Strip Processing Templates",
- "css_processing.add": "Add Strip Processing Template",
- "css_processing.edit": "Edit Strip Processing Template",
- "css_processing.name": "Template Name:",
- "css_processing.name_placeholder": "My Strip Processing Template",
- "css_processing.description_label": "Description (optional):",
- "css_processing.description_placeholder": "Describe this template...",
- "css_processing.created": "Strip processing template created",
- "css_processing.updated": "Strip processing template updated",
- "css_processing.deleted": "Strip processing template deleted",
- "css_processing.delete.confirm": "Are you sure you want to delete this strip processing template?",
- "css_processing.error.required": "Please fill in all required fields",
- "css_processing.error.load": "Error loading strip processing template",
- "css_processing.error.delete": "Error deleting strip processing template",
- "css_processing.error.clone_failed": "Failed to clone strip processing template",
- "device.button.stream_selector": "Source Settings",
- "device.stream_settings.title": "Source Settings",
- "device.stream_selector.label": "Source:",
- "device.stream_selector.hint": "Select a source that defines what this device captures and processes",
- "device.stream_selector.none": "-- No source assigned --",
- "device.stream_selector.saved": "Source settings updated",
- "device.stream_settings.border_width": "Border Width (px):",
- "device.stream_settings.border_width_hint": "How many pixels from the screen edge to sample for LED colors (1-100)",
- "device.stream_settings.interpolation": "Interpolation Mode:",
- "device.stream_settings.interpolation.average": "Average",
- "device.stream_settings.interpolation.median": "Median",
- "device.stream_settings.interpolation.dominant": "Dominant",
- "device.stream_settings.interpolation_hint": "How to calculate LED color from sampled pixels",
- "device.stream_settings.smoothing": "Smoothing:",
- "device.stream_settings.smoothing_hint": "Temporal blending between frames (0=none, 1=full). Reduces flicker.",
- "device.tip.stream_selector": "Configure picture source and LED projection settings for this device",
- "streams.group.static_image": "Static Image",
- "streams.add.static_image": "Add Static Image Source",
- "streams.edit.static_image": "Edit Static Image Source",
- "streams.type.static_image": "Static Image",
- "streams.group.video": "Video",
- "streams.add.video": "Add Video Source",
- "streams.edit.video": "Edit Video Source",
- "picture_source.type.video": "Video",
- "picture_source.type.video.desc": "Stream frames from video file, URL, or YouTube",
- "picture_source.video.url": "Video URL:",
- "picture_source.video.url.hint": "Local file path, HTTP URL, or YouTube URL",
- "picture_source.video.url.placeholder": "https://example.com/video.mp4",
- "picture_source.video.loop": "Loop:",
- "picture_source.video.speed": "Playback Speed:",
- "picture_source.video.start_time": "Start Time (s):",
- "picture_source.video.end_time": "End Time (s):",
- "picture_source.video.resolution_limit": "Max Width (px):",
- "picture_source.video.resolution_limit.hint": "Downscale video at decode time for performance",
- "streams.image_source": "Image Source:",
- "streams.image_source.placeholder": "https://example.com/image.jpg or C:\\path\\to\\image.png",
- "streams.image_source.hint": "Enter a URL (http/https) or local file path to an image",
- "streams.validate_image.validating": "Validating...",
- "streams.validate_image.valid": "Image accessible",
- "streams.validate_image.invalid": "Image not accessible",
- "targets.title": "Targets",
- "targets.description": "Targets bridge color strip sources to output devices. Each target references a device and a color strip source.",
- "targets.subtab.wled": "LED",
- "targets.subtab.led": "LED",
- "targets.section.devices": "Devices",
- "targets.section.color_strips": "Color Strip Sources",
- "targets.section.targets": "Targets",
- "targets.section.specific_settings": "Specific Settings",
- "targets.section.advanced": "Advanced",
- "targets.add": "Add Target",
- "targets.edit": "Edit Target",
- "targets.loading": "Loading targets...",
- "targets.none": "No targets configured",
- "targets.failed": "Failed to load targets",
- "targets.name": "Target Name:",
- "targets.name.placeholder": "My Target",
- "targets.device": "Device:",
- "targets.device.hint": "Select the LED device to send data to",
- "targets.device.none": "-- Select a device --",
- "targets.color_strip_source": "Color Strip Source:",
- "targets.color_strip_source.hint": "Select the color strip source that provides LED colors for this target",
- "targets.no_css": "No source",
- "targets.source": "Source:",
- "targets.source.hint": "Which picture source to capture and process",
- "targets.source.none": "-- No source assigned --",
- "targets.metrics.pipeline": "Pipeline details",
- "targets.fps": "Target FPS:",
- "targets.fps.hint": "Target frames per second for capture and LED updates (1-90)",
- "targets.fps.rec": "Hardware max ≈ {fps} fps ({leds} LEDs)",
- "targets.border_width": "Border Width (px):",
- "targets.border_width.hint": "How many pixels from the screen edge to sample for LED colors (1-100)",
- "targets.interpolation": "Interpolation Mode:",
- "targets.interpolation.hint": "How to calculate LED color from sampled pixels",
- "targets.interpolation.average": "Average",
- "targets.interpolation.median": "Median",
- "targets.interpolation.dominant": "Dominant",
- "targets.smoothing": "Smoothing:",
- "targets.smoothing.hint": "Temporal blending between frames (0=none, 1=full). Reduces flicker.",
- "targets.keepalive_interval": "Keep Alive Interval:",
- "targets.keepalive_interval.hint": "How often to resend the last frame when the source is static, keeping the device in live mode (0.5-5.0s)",
- "targets.created": "Target created successfully",
- "targets.updated": "Target updated successfully",
- "targets.deleted": "Target deleted successfully",
- "targets.delete.confirm": "Are you sure you want to delete this target?",
- "targets.error.load": "Failed to load targets",
- "targets.error.required": "Please fill in all required fields",
- "targets.error.name_required": "Please enter a target name",
- "targets.error.delete": "Failed to delete target",
- "targets.button.start": "Start",
- "targets.button.stop": "Stop",
- "targets.status.processing": "Processing",
- "targets.status.idle": "Idle",
- "targets.status.error": "Error",
- "targets.metrics.actual_fps": "Actual FPS",
- "targets.metrics.target_fps": "Target FPS",
- "targets.metrics.frames": "Frames",
- "targets.metrics.errors": "Errors",
- "targets.subtab.key_colors": "Key Colors",
- "targets.section.key_colors": "Key Colors Targets",
- "kc.add": "Add Key Colors Target",
- "kc.edit": "Edit Key Colors Target",
- "kc.name": "Target Name:",
- "kc.name.placeholder": "My Key Colors Target",
- "kc.source": "Picture Source:",
- "kc.source.hint": "Which picture source to extract colors from",
- "kc.source.none": "-- No source assigned --",
- "kc.fps": "Extraction FPS:",
- "kc.fps.hint": "How many times per second to extract colors (1-60)",
- "kc.interpolation": "Color Mode:",
- "kc.interpolation.hint": "How to compute the key color from pixels in each rectangle",
- "kc.interpolation.average": "Average",
- "kc.interpolation.median": "Median",
- "kc.interpolation.dominant": "Dominant",
- "kc.interpolation.average.desc": "Mean of all pixel colors",
- "kc.interpolation.median.desc": "Middle color value per channel",
- "kc.interpolation.dominant.desc": "Most frequent color",
- "kc.smoothing": "Smoothing:",
- "kc.smoothing.hint": "Temporal blending between extractions (0=none, 1=full)",
- "kc.pattern_template": "Pattern Template:",
- "kc.pattern_template.hint": "Select the rectangle pattern to use for color extraction",
- "kc.pattern_template.none": "-- Select a pattern template --",
- "kc.brightness_vs": "Brightness Source:",
- "kc.brightness_vs.hint": "Optional value source that dynamically controls brightness each frame (multiplied with the manual brightness slider)",
- "kc.brightness_vs.none": "None (manual brightness only)",
- "kc.created": "Key colors target created successfully",
- "kc.updated": "Key colors target updated successfully",
- "kc.deleted": "Key colors target deleted successfully",
- "kc.delete.confirm": "Are you sure you want to delete this key colors target?",
- "kc.error.no_pattern": "Please select a pattern template",
- "kc.error.required": "Please fill in all required fields",
- "kc.colors.none": "No colors extracted yet",
- "kc.test": "Test",
- "kc.test.error": "Test failed",
- "targets.section.pattern_templates": "Pattern Templates",
- "pattern.add": "Add Pattern Template",
- "pattern.edit": "Edit Pattern Template",
- "pattern.name": "Template Name:",
- "pattern.name.placeholder": "My Pattern Template",
- "pattern.description_label": "Description (optional):",
- "pattern.description_placeholder": "Describe this pattern...",
- "pattern.rectangles": "Rectangles",
- "pattern.rect.name": "Name",
- "pattern.rect.x": "X",
- "pattern.rect.y": "Y",
- "pattern.rect.width": "W",
- "pattern.rect.height": "H",
- "pattern.rect.add": "Add Rectangle",
- "pattern.rect.remove": "Remove",
- "pattern.rect.empty": "No rectangles defined. Add at least one rectangle.",
- "pattern.created": "Pattern template created successfully",
- "pattern.updated": "Pattern template updated successfully",
- "pattern.deleted": "Pattern template deleted successfully",
- "pattern.delete.confirm": "Are you sure you want to delete this pattern template?",
- "pattern.delete.referenced": "Cannot delete: this template is referenced by a target",
- "pattern.error.required": "Please fill in all required fields",
- "pattern.visual_editor": "Visual Editor",
- "pattern.capture_bg": "Capture Background",
- "pattern.source_for_bg": "Source for Background:",
- "pattern.source_for_bg.none": "-- Select source --",
- "pattern.delete_selected": "Delete Selected",
- "pattern.name.hint": "A descriptive name for this rectangle layout",
- "pattern.description.hint": "Optional notes about where or how this pattern is used",
- "pattern.visual_editor.hint": "Click + buttons to add rectangles. Drag edges to resize, drag inside to move.",
- "pattern.rectangles.hint": "Fine-tune rectangle positions and sizes with exact coordinates (0.0 to 1.0)",
- "overlay.toggle": "Toggle screen overlay",
- "overlay.button.show": "Show overlay visualization",
- "overlay.button.hide": "Hide overlay visualization",
- "overlay.started": "Overlay visualization started",
- "overlay.stopped": "Overlay visualization stopped",
- "overlay.error.start": "Failed to start overlay",
- "overlay.error.stop": "Failed to stop overlay",
- "dashboard.title": "Dashboard",
- "dashboard.section.targets": "Targets",
- "dashboard.section.running": "Running",
- "dashboard.section.stopped": "Stopped",
- "dashboard.no_targets": "No targets configured",
- "dashboard.uptime": "Uptime",
- "dashboard.fps": "FPS",
- "dashboard.errors": "Errors",
- "dashboard.device": "Device",
- "dashboard.stop_all": "Stop All",
- "dashboard.failed": "Failed to load dashboard",
- "dashboard.section.automations": "Automations",
- "dashboard.section.scenes": "Scene Presets",
- "dashboard.section.sync_clocks": "Sync Clocks",
- "dashboard.targets": "Targets",
- "dashboard.section.performance": "System Performance",
- "dashboard.perf.cpu": "CPU",
- "dashboard.perf.ram": "RAM",
- "dashboard.perf.gpu": "GPU",
- "dashboard.perf.unavailable": "unavailable",
- "dashboard.perf.color": "Chart color",
- "dashboard.poll_interval": "Refresh interval",
- "automations.title": "Automations",
- "automations.empty": "No automations configured. Create one to automate scene activation.",
- "automations.add": "Add Automation",
- "automations.edit": "Edit Automation",
- "automations.delete.confirm": "Delete automation \"{name}\"?",
- "automations.name": "Name:",
- "automations.name.hint": "A descriptive name for this automation",
- "automations.name.placeholder": "My Automation",
- "automations.enabled": "Enabled:",
- "automations.enabled.hint": "Disabled automations won't activate even when conditions are met",
- "automations.condition_logic": "Condition Logic:",
- "automations.condition_logic.hint": "How multiple conditions are combined: ANY (OR) or ALL (AND)",
- "automations.condition_logic.or": "Any condition (OR)",
- "automations.condition_logic.and": "All conditions (AND)",
- "automations.condition_logic.or.desc": "Triggers when any condition matches",
- "automations.condition_logic.and.desc": "Triggers only when all match",
- "automations.conditions": "Conditions:",
- "automations.conditions.hint": "Rules that determine when this automation activates",
- "automations.conditions.add": "Add Condition",
- "automations.conditions.empty": "No conditions — automation is always active when enabled",
- "automations.condition.always": "Always",
- "automations.condition.always.desc": "Always active",
- "automations.condition.always.hint": "Automation activates immediately when enabled and stays active.",
- "automations.condition.startup": "Startup",
- "automations.condition.startup.desc": "On server start",
- "automations.condition.startup.hint": "Activates when the server starts and stays active while enabled.",
- "automations.condition.application": "Application",
- "automations.condition.application.desc": "App running/focused",
- "automations.condition.application.apps": "Applications:",
- "automations.condition.application.apps.hint": "Process names, one per line (e.g. firefox.exe)",
- "automations.condition.application.browse": "Browse",
- "automations.condition.application.search": "Filter processes...",
- "automations.condition.application.no_processes": "No processes found",
- "automations.condition.application.match_type": "Match Type:",
- "automations.condition.application.match_type.hint": "How to detect the application",
- "automations.condition.application.match_type.running": "Running",
- "automations.condition.application.match_type.running.desc": "Process is active",
- "automations.condition.application.match_type.topmost": "Topmost",
- "automations.condition.application.match_type.topmost.desc": "Foreground window",
- "automations.condition.application.match_type.topmost_fullscreen": "Topmost + FS",
- "automations.condition.application.match_type.topmost_fullscreen.desc": "Foreground + fullscreen",
- "automations.condition.application.match_type.fullscreen": "Fullscreen",
- "automations.condition.application.match_type.fullscreen.desc": "Any fullscreen app",
- "automations.condition.time_of_day": "Time of Day",
- "automations.condition.time_of_day.desc": "Time range",
- "automations.condition.time_of_day.start_time": "Start Time:",
- "automations.condition.time_of_day.end_time": "End Time:",
- "automations.condition.time_of_day.overnight_hint": "For overnight ranges (e.g. 22:00–06:00), set start time after end time.",
- "automations.condition.system_idle": "System Idle",
- "automations.condition.system_idle.desc": "User idle/active",
- "automations.condition.system_idle.idle_minutes": "Idle Timeout (minutes):",
- "automations.condition.system_idle.mode": "Trigger Mode:",
- "automations.condition.system_idle.when_idle": "When idle",
- "automations.condition.system_idle.when_active": "When active",
- "automations.condition.display_state": "Display State",
- "automations.condition.display_state.desc": "Monitor on/off",
- "automations.condition.display_state.state": "Monitor State:",
- "automations.condition.display_state.on": "On",
- "automations.condition.display_state.off": "Off (sleeping)",
- "automations.condition.mqtt": "MQTT",
- "automations.condition.mqtt.desc": "MQTT message",
- "automations.condition.mqtt.topic": "Topic:",
- "automations.condition.mqtt.payload": "Payload:",
- "automations.condition.mqtt.match_mode": "Match Mode:",
- "automations.condition.mqtt.match_mode.exact": "Exact",
- "automations.condition.mqtt.match_mode.contains": "Contains",
- "automations.condition.mqtt.match_mode.regex": "Regex",
- "automations.condition.mqtt.hint": "Activate when an MQTT topic receives a matching payload",
- "automations.condition.webhook": "Webhook",
- "automations.condition.webhook.desc": "HTTP callback",
- "automations.condition.webhook.hint": "Activate via an HTTP call from external services (Home Assistant, IFTTT, curl, etc.)",
- "automations.condition.webhook.url": "Webhook URL:",
- "automations.condition.webhook.copy": "Copy",
- "automations.condition.webhook.copied": "Copied!",
- "automations.condition.webhook.save_first": "Save the automation first to generate a webhook URL",
- "automations.scene": "Scene:",
- "automations.scene.hint": "Scene preset to activate when conditions are met",
- "automations.scene.search_placeholder": "Search scenes...",
- "automations.scene.none_selected": "None (no scene)",
- "automations.scene.none_available": "No scenes available",
- "automations.deactivation_mode": "Deactivation:",
- "automations.deactivation_mode.hint": "What happens when conditions stop matching",
- "automations.deactivation_mode.none": "None",
- "automations.deactivation_mode.none.desc": "Keep current state",
- "automations.deactivation_mode.revert": "Revert",
- "automations.deactivation_mode.revert.desc": "Restore previous state",
- "automations.deactivation_mode.fallback_scene": "Fallback",
- "automations.deactivation_mode.fallback_scene.desc": "Activate a fallback scene",
- "automations.deactivation_scene": "Fallback Scene:",
- "automations.deactivation_scene.hint": "Scene to activate when this automation deactivates",
- "automations.status.active": "Active",
- "automations.status.inactive": "Inactive",
- "automations.status.disabled": "Disabled",
- "automations.action.disable": "Disable",
- "automations.last_activated": "Last activated",
- "automations.logic.and": " AND ",
- "automations.logic.or": " OR ",
- "automations.logic.all": "ALL",
- "automations.logic.any": "ANY",
- "automations.updated": "Automation updated",
- "automations.created": "Automation created",
- "automations.deleted": "Automation deleted",
- "automations.error.name_required": "Name is required",
- "automations.error.clone_failed": "Failed to clone automation",
- "scenes.title": "Scenes",
- "scenes.add": "Capture Scene",
- "scenes.edit": "Edit Scene",
- "scenes.name": "Name:",
- "scenes.name.hint": "A descriptive name for this scene preset",
- "scenes.name.placeholder": "My Scene",
- "scenes.description": "Description:",
- "scenes.description.hint": "Optional description of what this scene does",
- "scenes.targets": "Targets:",
- "scenes.targets.hint": "Select which targets to include in this scene snapshot",
- "scenes.targets.add": "Add Target",
- "scenes.targets.search_placeholder": "Search targets...",
- "scenes.capture": "Capture",
- "scenes.activate": "Activate scene",
- "scenes.recapture": "Recapture current state",
- "scenes.delete": "Delete scene",
- "scenes.targets_count": "targets",
- "scenes.captured": "Scene captured",
- "scenes.updated": "Scene updated",
- "scenes.activated": "Scene activated",
- "scenes.activated_partial": "Scene partially activated",
- "scenes.errors": "errors",
- "scenes.recaptured": "Scene recaptured",
- "scenes.deleted": "Scene deleted",
- "scenes.recapture_confirm": "Recapture current state into \"{name}\"?",
- "scenes.delete_confirm": "Delete scene \"{name}\"?",
- "scenes.error.name_required": "Name is required",
- "scenes.error.save_failed": "Failed to save scene",
- "scenes.error.activate_failed": "Failed to activate scene",
- "scenes.error.recapture_failed": "Failed to recapture scene",
- "scenes.error.delete_failed": "Failed to delete scene",
- "scenes.cloned": "Scene cloned",
- "scenes.error.clone_failed": "Failed to clone scene",
- "time.hours_minutes": "{h}h {m}m",
- "time.minutes_seconds": "{m}m {s}s",
- "time.seconds": "{s}s",
- "dashboard.type.led": "LED",
- "dashboard.type.kc": "Key Colors",
- "aria.close": "Close",
- "aria.save": "Save",
- "aria.cancel": "Cancel",
- "aria.previous": "Previous",
- "aria.next": "Next",
- "aria.hint": "Show hint",
- "color_strip.select_type": "Select Color Strip Type",
- "color_strip.add": "Add Color Strip Source",
- "color_strip.edit": "Edit Color Strip Source",
- "color_strip.name": "Name:",
- "color_strip.name.placeholder": "Wall Strip",
- "color_strip.picture_source": "Picture Source:",
- "color_strip.picture_source.hint": "Which screen capture source to use as input for LED color calculation",
- "color_strip.fps": "Target FPS:",
- "color_strip.fps.hint": "Target frames per second for LED color updates (10-90)",
- "color_strip.interpolation": "Color Mode:",
- "color_strip.interpolation.hint": "How to calculate LED color from sampled border pixels",
- "color_strip.interpolation.average": "Average",
- "color_strip.interpolation.median": "Median",
- "color_strip.interpolation.dominant": "Dominant",
- "color_strip.interpolation.average.desc": "Blend all sampled pixels into a smooth color",
- "color_strip.interpolation.median.desc": "Pick the middle color, reducing outliers",
- "color_strip.interpolation.dominant.desc": "Use the most frequent color in the sample",
- "color_strip.smoothing": "Smoothing:",
- "color_strip.smoothing.hint": "Temporal blending between frames (0=none, 1=full). Reduces flicker.",
- "color_strip.frame_interpolation": "Frame Interpolation:",
- "color_strip.frame_interpolation.hint": "Blends between consecutive captured frames to produce output at the full target FPS even when capture rate is lower. Reduces visible stepping on slow ambient transitions.",
- "color_strip.color_corrections": "Color Corrections",
- "color_strip.brightness": "Brightness:",
- "color_strip.brightness.hint": "Output brightness multiplier (0=off, 1=unchanged, 2=double). Applied after color extraction.",
- "color_strip.saturation": "Saturation:",
- "color_strip.saturation.hint": "Color saturation (0=grayscale, 1=unchanged, 2=double saturation)",
- "color_strip.gamma": "Gamma:",
- "color_strip.gamma.hint": "Gamma correction (1=none, <1=brighter midtones, >1=darker midtones)",
- "color_strip.test_device": "Test on Device:",
- "color_strip.test_device.hint": "Select a device to send test pixels to when clicking edge toggles",
- "color_strip.leds": "LED count",
- "color_strip.led_count": "LED Count:",
- "color_strip.led_count.hint": "Total number of LEDs on the physical strip. For screen sources: 0 = auto from calibration (extra LEDs not mapped to edges will be black). For static color: set to match your device LED count.",
- "color_strip.created": "Color strip source created",
- "color_strip.updated": "Color strip source updated",
- "color_strip.deleted": "Color strip source deleted",
- "color_strip.delete.confirm": "Are you sure you want to delete this color strip source?",
- "color_strip.delete.referenced": "Cannot delete: this source is in use by a target",
- "color_strip.error.name_required": "Please enter a name",
- "color_strip.type": "Type:",
- "color_strip.type.hint": "Picture Source derives LED colors from a screen capture. Static Color fills all LEDs with a single constant color. Gradient distributes a color gradient across all LEDs. Color Cycle smoothly cycles through a user-defined list of colors. Composite stacks multiple sources as blended layers. Audio Reactive drives LEDs from real-time audio input. API Input receives raw LED colors from external clients via REST or WebSocket.",
- "color_strip.type.picture": "Picture Source",
- "color_strip.type.picture.desc": "Colors from screen capture",
- "color_strip.type.picture_advanced": "Multi-Monitor",
- "color_strip.type.picture_advanced.desc": "Line-based calibration across monitors",
- "color_strip.type.static": "Static Color",
- "color_strip.type.static.desc": "Single solid color fill",
- "color_strip.type.gradient": "Gradient",
- "color_strip.type.gradient.desc": "Smooth color transition across LEDs",
- "color_strip.type.color_cycle": "Color Cycle",
- "color_strip.type.color_cycle.desc": "Cycle through a list of colors",
- "color_strip.static_color": "Color:",
- "color_strip.static_color.hint": "The solid color that will be sent to all LEDs on the strip.",
- "color_strip.gradient.preview": "Gradient:",
- "color_strip.gradient.preview.hint": "Visual preview. Click the marker track below to add a stop. Drag markers to reposition.",
- "color_strip.gradient.stops": "Color Stops:",
- "color_strip.gradient.stops.hint": "Each stop defines a color at a relative position (0.0 = start, 1.0 = end). The ↔ button adds a right-side color to create a hard edge at that stop.",
- "color_strip.gradient.stops_count": "stops",
- "color_strip.gradient.add_stop": "+ Add Stop",
- "color_strip.gradient.position": "Position (0.0–1.0)",
- "color_strip.gradient.bidir.hint": "Add a second color on the right side of this stop to create a hard edge in the gradient.",
- "color_strip.gradient.min_stops": "Gradient must have at least 2 stops",
- "color_strip.gradient.preset": "Preset:",
- "color_strip.gradient.preset.hint": "Load a predefined gradient palette. Selecting a preset replaces the current stops.",
- "color_strip.gradient.preset.custom": "— Custom —",
- "color_strip.gradient.preset.rainbow": "Rainbow",
- "color_strip.gradient.preset.sunset": "Sunset",
- "color_strip.gradient.preset.ocean": "Ocean",
- "color_strip.gradient.preset.forest": "Forest",
- "color_strip.gradient.preset.fire": "Fire",
- "color_strip.gradient.preset.lava": "Lava",
- "color_strip.gradient.preset.aurora": "Aurora",
- "color_strip.gradient.preset.ice": "Ice",
- "color_strip.gradient.preset.warm": "Warm",
- "color_strip.gradient.preset.cool": "Cool",
- "color_strip.gradient.preset.neon": "Neon",
- "color_strip.gradient.preset.pastel": "Pastel",
- "color_strip.gradient.preset.save_button": "Save as preset…",
- "color_strip.gradient.preset.save_prompt": "Enter a name for this preset:",
- "color_strip.gradient.preset.saved": "Preset saved",
- "color_strip.gradient.preset.deleted": "Preset deleted",
- "color_strip.gradient.preset.apply": "Apply",
- "color_strip.animation": "Animation",
- "color_strip.animation.type": "Effect:",
- "color_strip.animation.type.hint": "Animation effect to apply.",
- "color_strip.animation.type.none": "None (no animation effect)",
- "color_strip.animation.type.none.desc": "Static colors with no animation",
- "color_strip.animation.type.breathing": "Breathing",
- "color_strip.animation.type.breathing.desc": "Smooth brightness fade in and out",
- "color_strip.animation.type.color_cycle": "Color Cycle",
- "color_strip.animation.type.gradient_shift": "Gradient Shift",
- "color_strip.animation.type.gradient_shift.desc": "Slides the gradient along the strip",
- "color_strip.animation.type.wave": "Wave",
- "color_strip.animation.type.wave.desc": "Sinusoidal brightness wave moving along the strip",
- "color_strip.animation.type.strobe": "Strobe",
- "color_strip.animation.type.strobe.desc": "Rapid on/off flashing",
- "color_strip.animation.type.sparkle": "Sparkle",
- "color_strip.animation.type.sparkle.desc": "Random LEDs flash briefly",
- "color_strip.animation.type.pulse": "Pulse",
- "color_strip.animation.type.pulse.desc": "Sharp brightness pulse with quick fade",
- "color_strip.animation.type.candle": "Candle",
- "color_strip.animation.type.candle.desc": "Warm flickering candle-like glow",
- "color_strip.animation.type.rainbow_fade": "Rainbow Fade",
- "color_strip.animation.type.rainbow_fade.desc": "Cycles through the entire hue spectrum",
- "color_strip.animation.speed": "Speed:",
- "color_strip.animation.speed.hint": "Animation speed multiplier. 1.0 ≈ one cycle per second for Breathing; higher values cycle faster.",
- "color_strip.color_cycle.colors": "Colors:",
- "color_strip.color_cycle.colors.hint": "List of colors to cycle through smoothly. At least 2 required. Default is a full rainbow spectrum.",
- "color_strip.color_cycle.add_color": "+ Add Color",
- "color_strip.color_cycle.speed": "Speed:",
- "color_strip.color_cycle.speed.hint": "Cycle speed multiplier. 1.0 ≈ one full cycle every 20 seconds; higher values cycle faster.",
- "color_strip.color_cycle.min_colors": "Color cycle must have at least 2 colors",
- "color_strip.type.effect": "Effect",
- "color_strip.type.effect.desc": "Procedural effects like fire, plasma, aurora",
- "color_strip.type.effect.hint": "Procedural LED effects (fire, meteor, plasma, noise, aurora) generated in real time.",
- "color_strip.type.composite": "Composite",
- "color_strip.type.composite.desc": "Stack and blend multiple sources",
- "color_strip.type.composite.hint": "Stack multiple color strip sources as layers with blend modes and opacity.",
- "color_strip.type.mapped": "Mapped",
- "color_strip.type.mapped.desc": "Assign sources to LED zones",
- "color_strip.type.mapped.hint": "Assign different color strip sources to different LED ranges (zones). Unlike composite which blends layers, mapped places sources side-by-side.",
- "color_strip.type.audio": "Audio Reactive",
- "color_strip.type.audio.desc": "LEDs driven by audio input",
- "color_strip.type.audio.hint": "LED colors driven by real-time audio input — system audio or microphone.",
- "color_strip.type.api_input": "API Input",
- "color_strip.type.api_input.desc": "Receive colors from external apps",
- "color_strip.type.api_input.hint": "Receives raw LED color arrays from external clients via REST POST or WebSocket. Use this to integrate with custom software, home automation, or any system that can send HTTP requests.",
- "color_strip.api_input.fallback_color": "Fallback Color:",
- "color_strip.api_input.fallback_color.hint": "Color to display when no data has been received within the timeout period. LEDs will show this color on startup and after the connection is lost.",
- "color_strip.api_input.timeout": "Timeout (seconds):",
- "color_strip.api_input.timeout.hint": "How long to wait for new color data before reverting to the fallback color. Set to 0 to never time out.",
- "color_strip.api_input.endpoints": "Push Endpoints:",
- "color_strip.api_input.endpoints.hint": "Use these URLs to push LED color data from your external application. REST accepts JSON, WebSocket accepts both JSON and raw binary frames.",
- "color_strip.api_input.save_first": "Save the source first to see the push endpoint URLs.",
- "color_strip.type.notification": "Notification",
- "color_strip.type.notification.desc": "One-shot effect on webhook trigger",
- "color_strip.type.notification.hint": "Fires a one-shot visual effect (flash, pulse, sweep) when triggered via a webhook. Designed for use as a composite layer over a persistent base source.",
- "color_strip.notification.effect": "Effect:",
- "color_strip.notification.effect.hint": "Visual effect when a notification fires. Flash fades linearly, Pulse uses a smooth bell curve, Sweep fills LEDs left-to-right then fades.",
- "color_strip.notification.effect.flash": "Flash",
- "color_strip.notification.effect.flash.desc": "Instant on, linear fade-out",
- "color_strip.notification.effect.pulse": "Pulse",
- "color_strip.notification.effect.pulse.desc": "Smooth bell-curve glow",
- "color_strip.notification.effect.sweep": "Sweep",
- "color_strip.notification.effect.sweep.desc": "Fills left-to-right then fades",
- "color_strip.notification.duration": "Duration (ms):",
- "color_strip.notification.duration.hint": "How long the notification effect plays, in milliseconds.",
- "color_strip.notification.default_color": "Default Color:",
- "color_strip.notification.default_color.hint": "Color used when the notification has no app-specific color mapping.",
- "color_strip.notification.filter_mode": "App Filter:",
- "color_strip.notification.filter_mode.hint": "Filter notifications by app name. Off = accept all, Whitelist = only listed apps, Blacklist = all except listed apps.",
- "color_strip.notification.filter_mode.off": "Off",
- "color_strip.notification.filter_mode.whitelist": "Whitelist",
- "color_strip.notification.filter_mode.blacklist": "Blacklist",
- "color_strip.notification.filter_mode.off.desc": "Accept all notifications",
- "color_strip.notification.filter_mode.whitelist.desc": "Only listed apps",
- "color_strip.notification.filter_mode.blacklist.desc": "All except listed apps",
- "color_strip.notification.filter_list": "App List:",
- "color_strip.notification.filter_list.hint": "One app name per line. Use Browse to pick from running processes.",
- "color_strip.notification.filter_list.placeholder": "Discord\nSlack\nTelegram",
- "color_strip.notification.app_colors": "App Colors",
- "color_strip.notification.app_colors.label": "Color Mappings:",
- "color_strip.notification.app_colors.hint": "Per-app color overrides. Each row maps an app name to a specific notification color.",
- "color_strip.notification.app_colors.add": "+ Add Mapping",
- "color_strip.notification.endpoint": "Webhook Endpoint:",
- "color_strip.notification.endpoint.hint": "Use this URL to trigger notifications from external systems. POST with optional JSON body: {\"app\": \"AppName\", \"color\": \"#FF0000\"}.",
- "color_strip.notification.save_first": "Save the source first to see the webhook endpoint URL.",
- "color_strip.notification.app_count": "apps",
- "color_strip.notification.test": "Test notification",
- "color_strip.notification.test.ok": "Notification sent",
- "color_strip.notification.test.no_streams": "No running streams for this source",
- "color_strip.notification.test.error": "Failed to send notification",
- "color_strip.notification.history.title": "Notification History",
- "color_strip.notification.history.hint": "Recent OS notifications captured by the listener (newest first). Up to 50 entries.",
- "color_strip.notification.history.empty": "No notifications captured yet",
- "color_strip.notification.history.unavailable": "OS notification listener is not available on this platform",
- "color_strip.notification.history.error": "Failed to load notification history",
- "color_strip.notification.history.refresh": "Refresh",
- "color_strip.notification.history.unknown_app": "Unknown app",
- "color_strip.notification.history.fired": "Streams triggered",
- "color_strip.notification.history.filtered": "Streams filtered",
- "color_strip.test.title": "Test Preview",
- "color_strip.test.connecting": "Connecting...",
- "color_strip.test.error": "Failed to connect to preview stream",
- "color_strip.test.led_count": "LEDs:",
- "color_strip.test.fps": "FPS:",
- "color_strip.test.receive_fps": "Receive FPS",
- "color_strip.test.apply": "Apply",
- "color_strip.test.composite": "Composite",
- "color_strip.preview.title": "Live Preview",
- "color_strip.preview.not_connected": "Not connected",
- "color_strip.preview.connecting": "Connecting...",
- "color_strip.preview.connected": "Connected",
- "color_strip.preview.unsupported": "Preview not available for this source type",
- "color_strip.type.daylight": "Daylight Cycle",
- "color_strip.type.daylight.desc": "Simulates natural daylight over 24 hours",
- "color_strip.type.daylight.hint": "Simulates the sun's color temperature throughout a 24-hour day/night cycle — from warm sunrise to cool daylight to warm sunset and dim night.",
- "color_strip.daylight.speed": "Speed:",
- "color_strip.daylight.speed.hint": "Cycle speed multiplier. 1.0 = full day/night cycle in ~4 minutes. Higher values cycle faster.",
- "color_strip.daylight.use_real_time": "Use Real Time:",
- "color_strip.daylight.use_real_time.hint": "When enabled, LED color matches the actual time of day on this computer. Speed setting is ignored.",
- "color_strip.daylight.real_time": "Real Time",
- "color_strip.daylight.latitude": "Latitude:",
- "color_strip.daylight.latitude.hint": "Your geographic latitude (-90 to 90). Affects sunrise/sunset timing in real-time mode.",
- "color_strip.type.candlelight": "Candlelight",
- "color_strip.type.candlelight.desc": "Realistic flickering candle simulation",
- "color_strip.type.candlelight.hint": "Simulates realistic candle flickering across all LEDs with warm tones and organic flicker patterns.",
- "color_strip.candlelight.color": "Base Color:",
- "color_strip.candlelight.color.hint": "The warm base color of the candle flame. Default is a natural warm amber.",
- "color_strip.candlelight.intensity": "Flicker Intensity:",
- "color_strip.candlelight.intensity.hint": "How much the candles flicker. Low values produce a gentle glow, high values simulate a windy candle.",
- "color_strip.candlelight.num_candles_label": "Number of Candles:",
- "color_strip.candlelight.num_candles": "candles",
- "color_strip.candlelight.num_candles.hint": "How many independent candle sources along the strip. Each flickers with its own pattern.",
- "color_strip.candlelight.speed": "Flicker Speed:",
- "color_strip.candlelight.speed.hint": "Speed of the flicker animation. Higher values produce faster, more restless flames.",
- "color_strip.type.processed": "Processed",
- "color_strip.type.processed.desc": "Apply a processing template to another source",
- "color_strip.type.processed.hint": "Wraps an existing color strip source and pipes its output through a filter chain.",
- "color_strip.processed.input": "Source:",
- "color_strip.processed.input.hint": "The color strip source whose output will be processed",
- "color_strip.processed.template": "Processing Template:",
- "color_strip.processed.template.hint": "Filter chain to apply to the input source output",
- "color_strip.processed.error.no_input": "Please select an input source",
- "color_strip.composite.layers": "Layers:",
- "color_strip.composite.layers.hint": "Stack multiple color strip sources. First layer is the bottom, last is the top. Each layer can have its own blend mode and opacity.",
- "color_strip.composite.add_layer": "+ Add Layer",
- "color_strip.composite.source": "Source",
- "color_strip.composite.blend_mode": "Blend",
- "color_strip.composite.blend_mode.normal": "Normal",
- "color_strip.composite.blend_mode.normal.desc": "Standard alpha blending",
- "color_strip.composite.blend_mode.add": "Add",
- "color_strip.composite.blend_mode.add.desc": "Brightens by adding colors",
- "color_strip.composite.blend_mode.multiply": "Multiply",
- "color_strip.composite.blend_mode.multiply.desc": "Darkens by multiplying colors",
- "color_strip.composite.blend_mode.screen": "Screen",
- "color_strip.composite.blend_mode.screen.desc": "Brightens, inverse of multiply",
- "color_strip.composite.blend_mode.override": "Override",
- "color_strip.composite.blend_mode.override.desc": "Black = transparent, bright = opaque",
- "color_strip.composite.opacity": "Opacity",
- "color_strip.composite.brightness": "Brightness",
- "color_strip.composite.brightness.none": "None (full brightness)",
- "color_strip.composite.processing": "Processing",
- "color_strip.composite.enabled": "Enabled",
- "color_strip.composite.error.min_layers": "At least 1 layer is required",
- "color_strip.composite.error.no_source": "Each layer must have a source selected",
- "color_strip.composite.layers_count": "layers",
- "color_strip.mapped.zones": "Zones:",
- "color_strip.mapped.zones.hint": "Each zone maps a color strip source to a specific LED range. Zones are placed side-by-side — gaps between zones stay black.",
- "color_strip.mapped.add_zone": "+ Add Zone",
- "color_strip.mapped.zone_source": "Source",
- "color_strip.mapped.zone_start": "Start LED",
- "color_strip.mapped.zone_end": "End LED",
- "color_strip.mapped.zone_reverse": "Reverse",
- "color_strip.mapped.zones_count": "zones",
- "color_strip.mapped.select_source": "Search sources...",
- "color_strip.mapped.error.no_source": "Each zone must have a source selected",
- "color_strip.audio.visualization": "Visualization:",
- "color_strip.audio.visualization.hint": "How audio data is rendered to LEDs.",
- "color_strip.audio.viz.spectrum": "Spectrum Analyzer",
- "color_strip.audio.viz.spectrum.desc": "Frequency bars across the strip",
- "color_strip.audio.viz.beat_pulse": "Beat Pulse",
- "color_strip.audio.viz.beat_pulse.desc": "All LEDs pulse on the beat",
- "color_strip.audio.viz.vu_meter": "VU Meter",
- "color_strip.audio.viz.vu_meter.desc": "Volume level fills the strip",
- "color_strip.audio.source": "Audio Source:",
- "color_strip.audio.source.hint": "Audio source for this visualization. Can be a multichannel (device) or mono (single channel) source. Create and manage audio sources in the Sources tab.",
- "color_strip.audio.sensitivity": "Sensitivity:",
- "color_strip.audio.sensitivity.hint": "Gain multiplier for audio levels. Higher values make LEDs react to quieter sounds.",
- "color_strip.audio.smoothing": "Smoothing:",
- "color_strip.audio.smoothing.hint": "Temporal smoothing between frames. Higher values produce smoother but slower-reacting visuals.",
- "color_strip.audio.palette": "Palette:",
- "color_strip.audio.palette.hint": "Color palette used for spectrum bars or beat pulse coloring.",
- "color_strip.audio.color": "Base Color:",
- "color_strip.audio.color.hint": "Low-level color for VU meter bar.",
- "color_strip.audio.color_peak": "Peak Color:",
- "color_strip.audio.color_peak.hint": "High-level color at the top of the VU meter bar.",
- "color_strip.audio.mirror": "Mirror:",
- "color_strip.audio.mirror.hint": "Mirror spectrum from center outward: bass in the middle, treble at the edges.",
- "color_strip.effect.type": "Effect Type:",
- "color_strip.effect.type.hint": "Choose the procedural algorithm.",
- "color_strip.effect.fire": "Fire",
- "color_strip.effect.fire.desc": "Cellular automaton simulating rising flames with heat diffusion",
- "color_strip.effect.meteor": "Meteor",
- "color_strip.effect.meteor.desc": "Bright head travels along the strip with an exponential-decay tail",
- "color_strip.effect.plasma": "Plasma",
- "color_strip.effect.plasma.desc": "Overlapping sine waves mapped to a palette — classic demo-scene effect",
- "color_strip.effect.noise": "Noise",
- "color_strip.effect.noise.desc": "Scrolling fractal value noise mapped to a palette",
- "color_strip.effect.aurora": "Aurora",
- "color_strip.effect.aurora.desc": "Layered noise bands that drift and blend — northern lights style",
- "color_strip.effect.speed": "Speed:",
- "color_strip.effect.speed.hint": "Speed multiplier for the effect animation (0.1 = very slow, 10.0 = very fast).",
- "color_strip.effect.palette": "Palette:",
- "color_strip.effect.palette.hint": "Color palette used to map effect values to RGB colors.",
- "color_strip.effect.color": "Meteor Color:",
- "color_strip.effect.color.hint": "Head color for the meteor effect.",
- "color_strip.effect.intensity": "Intensity:",
- "color_strip.effect.intensity.hint": "Effect intensity — controls spark rate (fire), tail decay (meteor), or brightness range (aurora).",
- "color_strip.effect.scale": "Scale:",
- "color_strip.effect.scale.hint": "Spatial scale — wave frequency (plasma), zoom level (noise), or band width (aurora).",
- "color_strip.effect.mirror": "Mirror:",
- "color_strip.effect.mirror.hint": "Bounce mode — the meteor reverses direction at strip ends instead of wrapping.",
- "color_strip.palette.fire": "Fire",
- "color_strip.palette.ocean": "Ocean",
- "color_strip.palette.lava": "Lava",
- "color_strip.palette.forest": "Forest",
- "color_strip.palette.rainbow": "Rainbow",
- "color_strip.palette.aurora": "Aurora",
- "color_strip.palette.sunset": "Sunset",
- "color_strip.palette.ice": "Ice",
- "audio_source.title": "Audio Sources",
- "audio_source.group.multichannel": "Multichannel",
- "audio_source.group.mono": "Mono",
- "audio_source.add": "Add Audio Source",
- "audio_source.add.multichannel": "Add Multichannel Source",
- "audio_source.add.mono": "Add Mono Source",
- "audio_source.edit": "Edit Audio Source",
- "audio_source.edit.multichannel": "Edit Multichannel Source",
- "audio_source.edit.mono": "Edit Mono Source",
- "audio_source.name": "Name:",
- "audio_source.name.placeholder": "System Audio",
- "audio_source.name.hint": "A descriptive name for this audio source",
- "audio_source.type": "Type:",
- "audio_source.type.hint": "Multichannel captures all channels from a physical audio device. Mono extracts a single channel from a multichannel source.",
- "audio_source.type.multichannel": "Multichannel",
- "audio_source.type.mono": "Mono",
- "audio_source.device": "Audio Device:",
- "audio_source.device.hint": "Audio input source. Loopback devices capture system audio output; input devices capture microphone or line-in.",
- "audio_source.refresh_devices": "Refresh devices",
- "audio_source.parent": "Parent Source:",
- "audio_source.parent.hint": "Multichannel source to extract a channel from",
- "audio_source.channel": "Channel:",
- "audio_source.channel.hint": "Which audio channel to extract from the multichannel source",
- "audio_source.channel.mono": "Mono (L+R mix)",
- "audio_source.channel.left": "Left",
- "audio_source.channel.right": "Right",
- "audio_source.description": "Description (optional):",
- "audio_source.description.placeholder": "Describe this audio source...",
- "audio_source.description.hint": "Optional notes about this audio source",
- "audio_source.created": "Audio source created",
- "audio_source.updated": "Audio source updated",
- "audio_source.deleted": "Audio source deleted",
- "audio_source.delete.confirm": "Are you sure you want to delete this audio source?",
- "audio_source.error.name_required": "Please enter a name",
- "audio_source.audio_template": "Audio Template:",
- "audio_source.audio_template.hint": "Audio capture template that defines which engine and settings to use for this device",
- "audio_source.test": "Test",
- "audio_source.test.title": "Test Audio Source",
- "audio_source.test.rms": "RMS",
- "audio_source.test.peak": "Peak",
- "audio_source.test.beat": "Beat",
- "audio_source.test.connecting": "Connecting...",
- "audio_source.test.error": "Audio test failed",
- "audio_template.test": "Test",
- "audio_template.test.title": "Test Audio Template",
- "audio_template.test.device": "Audio Device:",
- "audio_template.test.device.hint": "Select which audio device to capture from during the test",
- "audio_template.test.run": "Run",
- "audio_template.title": "Audio Templates",
- "audio_template.add": "Add Audio Template",
- "audio_template.edit": "Edit Audio Template",
- "audio_template.name": "Template Name:",
- "audio_template.name.placeholder": "My Audio Template",
- "audio_template.description.label": "Description (optional):",
- "audio_template.description.placeholder": "Describe this template...",
- "audio_template.engine": "Audio Engine:",
- "audio_template.engine.hint": "Select the audio capture backend to use. WASAPI is Windows-only with loopback support. Sounddevice is cross-platform.",
- "audio_template.engine.unavailable": "Unavailable",
- "audio_template.engine.unavailable.hint": "This engine is not available on your system",
- "audio_template.config": "Configuration",
- "audio_template.config.show": "Show configuration",
- "audio_template.created": "Audio template created",
- "audio_template.updated": "Audio template updated",
- "audio_template.deleted": "Audio template deleted",
- "audio_template.delete.confirm": "Are you sure you want to delete this audio template?",
- "audio_template.error.load": "Failed to load audio templates",
- "audio_template.error.engines": "Failed to load audio engines",
- "audio_template.error.required": "Please fill in all required fields",
- "audio_template.error.delete": "Failed to delete audio template",
- "streams.group.value": "Value Sources",
- "streams.group.sync": "Sync Clocks",
- "tree.group.picture": "Picture Source",
- "tree.group.capture": "Screen Capture",
- "tree.group.static": "Static",
- "tree.group.processing": "Processed",
- "tree.group.strip": "Color Strip",
- "tree.group.audio": "Audio",
- "tree.group.utility": "Utility",
- "tree.leaf.sources": "Sources",
- "tree.leaf.engine_templates": "Engine Templates",
- "tree.leaf.images": "Images",
- "tree.leaf.video": "Video",
- "tree.leaf.filter_templates": "Filter Templates",
- "tree.leaf.processing_templates": "Processing Templates",
- "tree.leaf.templates": "Templates",
- "value_source.group.title": "Value Sources",
- "value_source.select_type": "Select Value Source Type",
- "value_source.add": "Add Value Source",
- "value_source.edit": "Edit Value Source",
- "value_source.name": "Name:",
- "value_source.name.placeholder": "Brightness Pulse",
- "value_source.name.hint": "A descriptive name for this value source",
- "value_source.type": "Type:",
- "value_source.type.hint": "Static outputs a constant value. Animated cycles through a waveform. Audio reacts to sound input. Adaptive types adjust brightness automatically based on time of day or scene content.",
- "value_source.type.static": "Static",
- "value_source.type.static.desc": "Constant output value",
- "value_source.type.animated": "Animated",
- "value_source.type.animated.desc": "Cycles through a waveform",
- "value_source.type.audio": "Audio",
- "value_source.type.audio.desc": "Reacts to sound input",
- "value_source.type.adaptive_time": "Adaptive (Time)",
- "value_source.type.adaptive_time.desc": "Adjusts by time of day",
- "value_source.type.adaptive_scene": "Adaptive (Scene)",
- "value_source.type.adaptive_scene.desc": "Adjusts by scene content",
- "value_source.type.daylight": "Daylight Cycle",
- "value_source.type.daylight.desc": "Brightness follows day/night cycle",
- "value_source.daylight.speed": "Speed:",
- "value_source.daylight.speed.hint": "Cycle speed multiplier. 1.0 = full day/night cycle in ~4 minutes. Higher values cycle faster.",
- "value_source.daylight.use_real_time": "Use Real Time:",
- "value_source.daylight.use_real_time.hint": "When enabled, brightness follows the actual time of day. Speed is ignored.",
- "value_source.daylight.enable_real_time": "Follow wall clock",
- "value_source.daylight.latitude": "Latitude:",
- "value_source.daylight.latitude.hint": "Your geographic latitude (-90 to 90). Affects sunrise/sunset timing in real-time mode.",
- "value_source.daylight.real_time": "Real-time",
- "value_source.daylight.speed_label": "Speed",
- "value_source.value": "Value:",
- "value_source.value.hint": "Constant output value (0.0 = off, 1.0 = full brightness)",
- "value_source.waveform": "Waveform:",
- "value_source.waveform.hint": "Shape of the brightness animation cycle",
- "value_source.waveform.sine": "Sine",
- "value_source.waveform.triangle": "Triangle",
- "value_source.waveform.square": "Square",
- "value_source.waveform.sawtooth": "Sawtooth",
- "value_source.speed": "Speed (cpm):",
- "value_source.speed.hint": "Cycles per minute — how fast the waveform repeats (1 = very slow, 120 = very fast)",
- "value_source.min_value": "Min Value:",
- "value_source.min_value.hint": "Minimum output of the waveform cycle",
- "value_source.max_value": "Max Value:",
- "value_source.max_value.hint": "Maximum output of the waveform cycle",
- "value_source.audio_source": "Audio Source:",
- "value_source.audio_source.hint": "Audio source to read audio levels from (multichannel or mono)",
- "value_source.mode": "Mode:",
- "value_source.mode.hint": "RMS measures average volume. Peak tracks loudest moments. Beat triggers on rhythm.",
- "value_source.mode.rms": "RMS (Volume)",
- "value_source.mode.peak": "Peak",
- "value_source.mode.beat": "Beat",
- "value_source.mode.rms.desc": "Average volume level",
- "value_source.mode.peak.desc": "Loudest moment tracking",
- "value_source.mode.beat.desc": "Rhythm pulse detection",
- "value_source.auto_gain": "Auto Gain:",
- "value_source.auto_gain.hint": "Automatically normalize audio levels so output uses the full range, regardless of input volume",
- "value_source.auto_gain.enable": "Enable auto-gain",
- "value_source.sensitivity": "Sensitivity:",
- "value_source.sensitivity.hint": "Gain multiplier for the audio signal (higher = more reactive)",
- "value_source.scene_sensitivity.hint": "Gain multiplier for the luminance signal (higher = more reactive to brightness changes)",
- "value_source.smoothing": "Smoothing:",
- "value_source.smoothing.hint": "Temporal smoothing (0 = instant response, 1 = very smooth/slow)",
- "value_source.audio_min_value": "Min Value:",
- "value_source.audio_min_value.hint": "Output when audio is silent (e.g. 0.3 = 30% brightness floor)",
- "value_source.audio_max_value": "Max Value:",
- "value_source.audio_max_value.hint": "Output at maximum audio level",
- "value_source.schedule": "Schedule:",
- "value_source.schedule.hint": "Define at least 2 time points. Brightness interpolates linearly between them, wrapping at midnight.",
- "value_source.schedule.add": "+ Add Point",
- "value_source.schedule.points": "points",
- "value_source.picture_source": "Picture Source:",
- "value_source.picture_source.hint": "The picture source whose frames will be analyzed for average brightness.",
- "value_source.scene_behavior": "Behavior:",
- "value_source.scene_behavior.hint": "Complement: dark scene = high brightness (ideal for ambient backlight). Match: bright scene = high brightness.",
- "value_source.scene_behavior.complement": "Complement (dark → bright)",
- "value_source.scene_behavior.match": "Match (bright → bright)",
- "value_source.adaptive_min_value": "Min Value:",
- "value_source.adaptive_min_value.hint": "Minimum output brightness",
- "value_source.adaptive_max_value": "Max Value:",
- "value_source.adaptive_max_value.hint": "Maximum output brightness",
- "value_source.error.schedule_min": "Schedule requires at least 2 time points",
- "value_source.description": "Description (optional):",
- "value_source.description.placeholder": "Describe this value source...",
- "value_source.description.hint": "Optional notes about this value source",
- "value_source.created": "Value source created",
- "value_source.updated": "Value source updated",
- "value_source.deleted": "Value source deleted",
- "value_source.delete.confirm": "Are you sure you want to delete this value source?",
- "value_source.error.name_required": "Please enter a name",
- "value_source.test": "Test",
- "value_source.test.title": "Test Value Source",
- "value_source.test.connecting": "Connecting...",
- "value_source.test.error": "Failed to connect",
- "value_source.test.current": "Current",
- "value_source.test.min": "Min",
- "value_source.test.max": "Max",
- "test.frames": "Frames",
- "test.fps": "FPS",
- "test.avg_capture": "Avg",
- "targets.brightness_vs": "Brightness Source:",
- "targets.brightness_vs.hint": "Optional value source that dynamically controls brightness each frame (overrides device brightness)",
- "targets.brightness_vs.none": "None (device brightness)",
- "targets.min_brightness_threshold": "Min Brightness Threshold:",
- "targets.min_brightness_threshold.hint": "Effective output brightness (pixel brightness × device/source brightness) below this value turns LEDs off completely (0 = disabled)",
- "targets.adaptive_fps": "Adaptive FPS:",
- "targets.adaptive_fps.hint": "Automatically reduce send rate when the device becomes unresponsive, and gradually recover when it stabilizes. Recommended for WiFi devices with weak signal.",
- "targets.protocol": "Protocol:",
- "targets.protocol.hint": "DDP sends pixels via fast UDP (recommended for most setups). HTTP uses the JSON API — slower but reliable, limited to ~500 LEDs.",
- "targets.protocol.ddp": "DDP (UDP)",
- "targets.protocol.ddp.desc": "Fast raw UDP packets — recommended",
- "targets.protocol.http": "HTTP",
- "targets.protocol.http.desc": "JSON API — slower, ≤500 LEDs",
- "targets.protocol.serial": "Serial",
- "search.open": "Search (Ctrl+K)",
- "search.placeholder": "Search entities... (Ctrl+K)",
- "search.loading": "Loading...",
- "search.no_results": "No results found",
- "search.group.devices": "Devices",
- "search.group.targets": "LED Targets",
- "search.group.kc_targets": "Key Colors Targets",
- "search.group.css": "Color Strip Sources",
- "search.group.automations": "Automations",
- "search.group.streams": "Picture Streams",
- "search.group.capture_templates": "Capture Templates",
- "search.group.pp_templates": "Post-Processing Templates",
- "search.group.pattern_templates": "Pattern Templates",
- "search.group.audio": "Audio Sources",
- "search.group.value": "Value Sources",
- "search.group.scenes": "Scene Presets",
- "search.group.cspt": "Strip Processing Templates",
- "search.group.sync_clocks": "Sync Clocks",
- "search.group.actions": "Actions",
- "search.action.start": "Start",
- "search.action.stop": "Stop",
- "search.action.activate": "Activate",
- "search.action.enable": "Enable",
- "search.action.disable": "Disable",
- "settings.backup.label": "Backup Configuration",
- "settings.backup.hint": "Download all configuration (devices, targets, streams, templates, automations) as a single JSON file.",
- "settings.backup.button": "Download Backup",
- "settings.backup.success": "Backup downloaded successfully",
- "settings.backup.error": "Backup download failed",
- "settings.restore.label": "Restore Configuration",
- "settings.restore.hint": "Upload a previously downloaded backup file to replace all configuration. The server will restart automatically.",
- "settings.restore.button": "Restore from Backup",
- "settings.restore.confirm": "This will replace ALL configuration and restart the server. Are you sure?",
- "settings.restore.success": "Configuration restored",
- "settings.restore.error": "Restore failed",
- "settings.restore.restarting": "Server is restarting...",
- "settings.restore.restart_timeout": "Server did not respond. Please refresh the page manually.",
- "settings.restart_server": "Restart Server",
- "settings.restart_confirm": "Restart the server? Active targets will be stopped.",
- "settings.restarting": "Restarting server...",
- "settings.button.close": "Close",
- "settings.log_level.label": "Log Level",
- "settings.log_level.hint": "Change the server log verbosity at runtime. DEBUG shows the most detail; CRITICAL shows only fatal errors.",
- "settings.log_level.save": "Apply",
- "settings.log_level.saved": "Log level changed",
- "settings.log_level.save_error": "Failed to change log level",
- "settings.log_level.desc.debug": "Verbose developer output",
- "settings.log_level.desc.info": "Normal operation messages",
- "settings.log_level.desc.warning": "Potential problems",
- "settings.log_level.desc.error": "Failures only",
- "settings.log_level.desc.critical": "Fatal errors only",
- "settings.auto_backup.label": "Auto-Backup",
- "settings.auto_backup.hint": "Automatically create periodic backups of all configuration. Old backups are pruned when the maximum count is reached.",
- "settings.auto_backup.enable": "Enable auto-backup",
- "settings.auto_backup.interval_label": "Interval",
- "settings.auto_backup.max_label": "Max backups",
- "settings.auto_backup.save": "Save Settings",
- "settings.auto_backup.saved": "Auto-backup settings saved",
- "settings.auto_backup.save_error": "Failed to save auto-backup settings",
- "settings.auto_backup.last_backup": "Last backup",
- "settings.auto_backup.never": "Never",
- "settings.saved_backups.label": "Saved Backups",
- "settings.saved_backups.hint": "Auto-backup files stored on the server. Download to save locally, or delete to free space.",
- "settings.saved_backups.empty": "No saved backups",
- "settings.saved_backups.restore": "Restore",
- "settings.saved_backups.download": "Download",
- "settings.saved_backups.delete": "Delete",
- "settings.saved_backups.delete_confirm": "Delete this backup file?",
- "settings.saved_backups.delete_error": "Failed to delete backup",
- "settings.saved_backups.type.auto": "auto",
- "settings.saved_backups.type.manual": "manual",
- "settings.mqtt.label": "MQTT",
- "settings.mqtt.hint": "Configure MQTT broker connection for automation conditions and triggers.",
- "settings.mqtt.enabled": "Enable MQTT",
- "settings.mqtt.host_label": "Broker Host",
- "settings.mqtt.port_label": "Port",
- "settings.mqtt.username_label": "Username",
- "settings.mqtt.password_label": "Password",
- "settings.mqtt.password_set_hint": "Password is set — leave blank to keep",
- "settings.mqtt.client_id_label": "Client ID",
- "settings.mqtt.base_topic_label": "Base Topic",
- "settings.mqtt.save": "Save MQTT Settings",
- "settings.mqtt.saved": "MQTT settings saved",
- "settings.mqtt.save_error": "Failed to save MQTT settings",
- "settings.mqtt.error_host_required": "Broker host is required",
- "settings.logs.label": "Server Logs",
- "settings.logs.hint": "Stream live server log output. Use the filter to show only relevant log levels.",
- "settings.logs.connect": "Connect",
- "settings.logs.disconnect": "Disconnect",
- "settings.logs.clear": "Clear",
- "settings.logs.error": "Log viewer connection failed",
- "settings.logs.filter.all": "All levels",
- "settings.logs.filter.info": "Info+",
- "settings.logs.filter.warning": "Warning+",
- "settings.logs.filter.error": "Error only",
- "settings.logs.filter.all_desc": "Show all log messages",
- "settings.logs.filter.info_desc": "Info, warning, and errors",
- "settings.logs.filter.warning_desc": "Warnings and errors only",
- "settings.logs.filter.error_desc": "Errors only",
- "device.error.power_off_failed": "Failed to turn off device",
- "device.removed": "Device removed",
- "device.error.remove_failed": "Failed to remove device",
- "device.error.settings_load_failed": "Failed to load device settings",
- "device.error.brightness": "Failed to update brightness",
- "device.error.required": "Please fill in all fields correctly",
- "device.error.update": "Failed to update device",
- "device.error.save": "Failed to save settings",
- "device.error.clone_failed": "Failed to clone device",
- "device_discovery.error.fill_all_fields": "Please fill in all fields",
- "device_discovery.added": "Device added successfully",
- "device_discovery.error.add_failed": "Failed to add device",
- "calibration.error.load_failed": "Failed to load calibration",
- "calibration.error.css_load_failed": "Failed to load color strip source",
- "calibration.error.test_toggle_failed": "Failed to toggle test edge",
- "calibration.saved": "Calibration saved",
- "calibration.error.save_failed": "Failed to save calibration",
- "calibration.error.led_count_mismatch": "Total LEDs must equal the device LED count",
- "calibration.error.led_count_exceeded": "Calibrated LEDs exceed the total LED count",
- "calibration.mode.simple": "Simple",
- "calibration.mode.advanced": "Advanced",
- "calibration.switch_to_advanced": "Switch to Advanced",
- "calibration.advanced.title": "Advanced Calibration",
- "calibration.advanced.switch_to_simple": "Switch to Simple",
- "calibration.advanced.lines_title": "Lines",
- "calibration.advanced.canvas_hint": "Drag monitors to reposition. Click edges to select lines. Scroll to zoom, drag empty space to pan.",
- "calibration.advanced.reset_view": "Reset view",
- "calibration.advanced.line_properties": "Line Properties",
- "calibration.advanced.picture_source": "Source:",
- "calibration.advanced.picture_source.hint": "The picture source (monitor) this line samples from",
- "calibration.advanced.edge": "Edge:",
- "calibration.advanced.edge.hint": "Which screen edge to sample pixels from",
- "calibration.advanced.led_count": "LEDs:",
- "calibration.advanced.led_count.hint": "Number of LEDs mapped to this line",
- "calibration.advanced.span_start": "Span Start:",
- "calibration.advanced.span_start.hint": "Where sampling begins along the edge (0 = start, 1 = end). Use to cover only part of an edge.",
- "calibration.advanced.span_end": "Span End:",
- "calibration.advanced.span_end.hint": "Where sampling ends along the edge (0 = start, 1 = end). Together with Span Start, defines the active portion.",
- "calibration.advanced.border_width": "Depth (px):",
- "calibration.advanced.border_width.hint": "How many pixels deep from the edge to sample. Larger values capture more of the screen interior.",
- "calibration.advanced.reverse": "Reverse",
- "calibration.advanced.no_lines_warning": "Add at least one line",
- "dashboard.error.automation_toggle_failed": "Failed to toggle automation",
- "dashboard.error.start_failed": "Failed to start processing",
- "dashboard.error.stop_failed": "Failed to stop processing",
- "dashboard.error.stop_all": "Failed to stop all targets",
- "target.error.editor_open_failed": "Failed to open target editor",
- "target.error.start_failed": "Failed to start target",
- "target.error.stop_failed": "Failed to stop target",
- "target.error.clone_failed": "Failed to clone target",
- "target.error.delete_failed": "Failed to delete target",
- "targets.stop_all.button": "Stop All",
- "targets.stop_all.none_running": "No targets are currently running",
- "targets.stop_all.stopped": "Stopped {count} target(s)",
- "targets.stop_all.error": "Failed to stop targets",
- "audio_source.error.load": "Failed to load audio source",
- "audio_template.error.clone_failed": "Failed to clone audio template",
- "value_source.error.load": "Failed to load value source",
- "color_strip.error.editor_open_failed": "Failed to open color strip editor",
- "color_strip.error.clone_failed": "Failed to clone color strip source",
- "color_strip.error.delete_failed": "Failed to delete color strip source",
- "pattern.error.editor_open_failed": "Failed to open pattern template editor",
- "pattern.error.clone_failed": "Failed to clone pattern template",
- "pattern.error.delete_failed": "Failed to delete pattern template",
- "pattern.error.capture_bg_failed": "Failed to capture background",
- "stream.error.clone_picture_failed": "Failed to clone picture source",
- "stream.error.clone_capture_failed": "Failed to clone capture template",
- "stream.error.clone_pp_failed": "Failed to clone postprocessing template",
- "kc_target.error.editor_open_failed": "Failed to open key colors editor",
- "kc_target.error.clone_failed": "Failed to clone key colors target",
- "kc_target.error.delete_failed": "Failed to delete key colors target",
- "theme.switched.dark": "Switched to dark theme",
- "theme.switched.light": "Switched to light theme",
- "accent.color.updated": "Accent color updated",
- "search.footer": "↑↓ navigate · Enter select · Esc close",
- "sync_clock.group.title": "Sync Clocks",
- "sync_clock.add": "Add Sync Clock",
- "sync_clock.edit": "Edit Sync Clock",
- "sync_clock.name": "Name:",
- "sync_clock.name.placeholder": "Main Animation Clock",
- "sync_clock.name.hint": "A descriptive name for this synchronization clock",
- "sync_clock.speed": "Speed:",
- "sync_clock.speed.hint": "Animation speed multiplier for all linked sources. 1.0 = normal, 2.0 = double speed, 0.5 = half speed.",
- "sync_clock.description": "Description (optional):",
- "sync_clock.description.placeholder": "Optional description",
- "sync_clock.description.hint": "Optional notes about this clock's purpose",
- "sync_clock.status.running": "Running",
- "sync_clock.status.paused": "Paused",
- "sync_clock.action.pause": "Pause",
- "sync_clock.action.resume": "Resume",
- "sync_clock.action.reset": "Reset",
- "sync_clock.error.name_required": "Clock name is required",
- "sync_clock.error.load": "Failed to load sync clock",
- "sync_clock.created": "Sync clock created",
- "sync_clock.updated": "Sync clock updated",
- "sync_clock.deleted": "Sync clock deleted",
- "sync_clock.paused": "Clock paused",
- "sync_clock.resumed": "Clock resumed",
- "sync_clock.reset_done": "Clock reset to zero",
- "sync_clock.delete.confirm": "Delete this sync clock? Linked sources will lose synchronization and run at default speed.",
- "sync_clock.elapsed": "Elapsed time",
- "color_strip.clock": "Sync Clock:",
- "color_strip.clock.hint": "Link to a sync clock to synchronize animation timing across sources. Speed is controlled on the clock.",
- "graph.title": "Graph",
- "graph.fit_all": "Fit all nodes",
- "graph.zoom_in": "Zoom in",
- "graph.zoom_out": "Zoom out",
- "graph.search": "Search nodes",
- "graph.search_placeholder": "Search entities...",
- "graph.legend": "Legend",
- "graph.minimap": "Minimap",
- "graph.relayout": "Re-layout",
- "graph.empty": "No entities yet",
- "graph.empty.hint": "Create devices, sources, and targets to see them here.",
- "graph.disconnect": "Disconnect",
- "graph.connection_updated": "Connection updated",
- "graph.connection_failed": "Failed to update connection",
- "graph.connection_removed": "Connection removed",
- "graph.disconnect_failed": "Failed to disconnect",
- "graph.relayout_confirm": "Reset all manual node positions and re-layout the graph?",
- "graph.fullscreen": "Toggle fullscreen",
- "graph.add_entity": "Add entity",
- "graph.color_picker": "Node color",
- "graph.filter": "Filter nodes",
- "graph.filter_placeholder": "Filter: name, type:x, tag:x",
- "graph.filter_clear": "Clear filter",
- "graph.filter_running": "Running",
- "graph.filter_stopped": "Stopped",
- "graph.filter_types": "Types",
- "graph.filter_group.capture": "Capture",
- "graph.filter_group.strip": "Color Strip",
- "graph.filter_group.audio": "Audio",
- "graph.filter_group.targets": "Targets",
- "graph.filter_group.other": "Other",
- "graph.bulk_delete_confirm": "Delete {count} selected entities?",
- "graph.nothing_to_undo": "Nothing to undo",
- "graph.nothing_to_redo": "Nothing to redo",
- "graph.help_title": "Keyboard Shortcuts",
- "graph.help.search": "Search",
- "graph.help.filter": "Filter",
- "graph.help.add": "Add entity",
- "graph.help.shortcuts": "Shortcuts",
- "graph.help.delete": "Delete / Detach",
- "graph.help.select_all": "Select all",
- "graph.help.undo": "Undo",
- "graph.help.redo": "Redo",
- "graph.help.fullscreen": "Fullscreen",
- "graph.help.deselect": "Deselect",
- "graph.help.navigate": "Navigate nodes",
- "graph.help.click": "Click",
- "graph.help.click_desc": "Select node",
- "graph.help.dblclick": "Double-click",
- "graph.help.dblclick_desc": "Zoom to node",
- "graph.help.shift_click": "Shift+Click",
- "graph.help.shift_click_desc": "Multi-select",
- "graph.help.shift_drag": "Shift+Drag",
- "graph.help.shift_drag_desc": "Rubber-band select",
- "graph.help.drag_node": "Drag node",
- "graph.help.drag_node_desc": "Reposition",
- "graph.help.drag_port": "Drag port",
- "graph.help.drag_port_desc": "Connect entities",
- "graph.help.right_click": "Right-click edge",
- "graph.help.right_click_desc": "Detach connection",
- "graph.tooltip.fps": "FPS",
- "graph.tooltip.errors": "Errors",
- "graph.tooltip.uptime": "Uptime",
- "automation.enabled": "Automation enabled",
- "automation.disabled": "Automation disabled",
- "scene_preset.activated": "Preset activated",
- "scene_preset.used_by": "Used by %d automation(s)",
- "settings.api_keys.label": "API Keys",
- "settings.api_keys.hint": "API keys are defined in the server config file (config.yaml). Edit the file and restart the server to apply changes.",
- "settings.api_keys.empty": "No API keys configured",
- "settings.api_keys.load_error": "Failed to load API keys",
- "settings.partial.label": "Partial Export / Import",
- "settings.partial.hint": "Export or import a single entity type. Import replaces or merges existing data and restarts the server.",
- "settings.partial.store.devices": "Devices",
- "settings.partial.store.output_targets": "LED Targets",
- "settings.partial.store.color_strip_sources": "Color Strips",
- "settings.partial.store.picture_sources": "Picture Sources",
- "settings.partial.store.audio_sources": "Audio Sources",
- "settings.partial.store.audio_templates": "Audio Templates",
- "settings.partial.store.capture_templates": "Capture Templates",
- "settings.partial.store.postprocessing_templates": "Post-processing Templates",
- "settings.partial.store.color_strip_processing_templates": "CSS Processing Templates",
- "settings.partial.store.pattern_templates": "Pattern Templates",
- "settings.partial.store.value_sources": "Value Sources",
- "settings.partial.store.sync_clocks": "Sync Clocks",
- "settings.partial.store.automations": "Automations",
- "settings.partial.store.scene_presets": "Scene Presets",
- "settings.partial.export_button": "Export",
- "settings.partial.import_button": "Import from File",
- "settings.partial.merge_label": "Merge (add/overwrite, keep existing)",
- "settings.partial.export_success": "Exported successfully",
- "settings.partial.export_error": "Export failed",
- "settings.partial.import_success": "Imported successfully",
- "settings.partial.import_error": "Import failed",
- "settings.partial.import_confirm_replace": "This will REPLACE all {store} data and restart the server. Continue?",
- "settings.partial.import_confirm_merge": "This will MERGE into existing {store} data and restart the server. Continue?",
- "section.empty.devices": "No devices yet. Click + to add one.",
- "section.empty.targets": "No LED targets yet. Click + to add one.",
- "section.empty.kc_targets": "No key color targets yet. Click + to add one.",
- "section.empty.pattern_templates": "No pattern templates yet. Click + to add one.",
- "section.empty.picture_sources": "No sources yet. Click + to add one.",
- "section.empty.capture_templates": "No capture templates yet. Click + to add one.",
- "section.empty.pp_templates": "No post-processing templates yet. Click + to add one.",
- "section.empty.audio_sources": "No audio sources yet. Click + to add one.",
- "section.empty.audio_templates": "No audio templates yet. Click + to add one.",
- "section.empty.color_strips": "No color strips yet. Click + to add one.",
- "section.empty.value_sources": "No value sources yet. Click + to add one.",
- "section.empty.sync_clocks": "No sync clocks yet. Click + to add one.",
- "section.empty.cspt": "No CSS processing templates yet. Click + to add one.",
- "section.empty.automations": "No automations yet. Click + to add one.",
- "section.empty.scenes": "No scene presets yet. Click + to add one.",
-
- "bulk.select": "Select",
- "bulk.cancel": "Cancel",
- "bulk.selected_count.one": "{count} selected",
- "bulk.selected_count.other": "{count} selected",
- "bulk.select_all": "Select all",
- "bulk.deselect_all": "Deselect all",
- "bulk.delete": "Delete",
- "bulk.start": "Start",
- "bulk.stop": "Stop",
- "bulk.enable": "Enable",
- "bulk.disable": "Disable",
- "bulk.confirm_delete.one": "Delete {count} item?",
- "bulk.confirm_delete.other": "Delete {count} items?"
-}
+ "app.title": "LED Grab",
+ "app.version": "Version:",
+ "app.api_docs": "API Documentation",
+ "app.connection_lost": "Server unreachable",
+ "app.connection_retrying": "Attempting to reconnect…",
+ "demo.badge": "DEMO",
+ "demo.banner": "You're in demo mode — all devices and data are virtual. No real hardware is used.",
+ "theme.toggle": "Toggle theme",
+ "bg.anim.toggle": "Toggle ambient background",
+ "accent.title": "Accent color",
+ "accent.custom": "Custom",
+ "accent.reset": "Reset",
+ "locale.change": "Change language",
+ "auth.login": "Login",
+ "auth.logout": "Logout",
+ "auth.authenticated": "● Authenticated",
+ "auth.title": "Login to LED Grab",
+ "auth.message": "Please enter your API key to authenticate and access the LED Grab.",
+ "auth.label": "API Key:",
+ "auth.placeholder": "Enter your API key...",
+ "auth.hint": "Your API key will be stored securely in your browser's local storage.",
+ "auth.button.cancel": "Cancel",
+ "auth.button.login": "Login",
+ "auth.error.required": "Please enter an API key",
+ "auth.success": "Logged in successfully!",
+ "auth.logout.confirm": "Are you sure you want to logout?",
+ "auth.logout.success": "Logged out successfully",
+ "auth.please_login": "Please login to view",
+ "auth.session_expired": "Your session has expired or the API key is invalid. Please login again.",
+ "auth.prompt_update": "Current API key is set. Enter new key to update or leave blank to remove:",
+ "auth.prompt_enter": "Enter your API key:",
+ "auth.toggle_password": "Toggle password visibility",
+ "api_key.login": "Login",
+ "displays.title": "Available Displays",
+ "displays.layout": "Displays",
+ "displays.information": "Display Information",
+ "displays.legend.primary": "Primary Display",
+ "displays.legend.secondary": "Secondary Display",
+ "displays.badge.primary": "Primary",
+ "displays.badge.secondary": "Secondary",
+ "displays.resolution": "Resolution:",
+ "displays.refresh_rate": "Refresh Rate:",
+ "displays.position": "Position:",
+ "displays.index": "Display Index:",
+ "displays.loading": "Loading displays...",
+ "displays.none": "No displays available",
+ "displays.failed": "Failed to load displays",
+ "displays.picker.title": "Select a Display",
+ "displays.picker.title.device": "Select a Device",
+ "displays.picker.select": "Select display...",
+ "displays.picker.click_to_select": "Click to select this display",
+ "displays.picker.adb_connect": "Connect ADB device",
+ "displays.picker.adb_connect.placeholder": "IP address (e.g. 192.168.2.201)",
+ "displays.picker.adb_connect.button": "Connect",
+ "displays.picker.adb_connect.success": "Device connected",
+ "displays.picker.adb_connect.error": "Failed to connect device",
+ "displays.picker.adb_disconnect": "Disconnect",
+ "displays.picker.no_android": "No Android devices found. Connect via USB or enter IP above.",
+ "templates.title": "Engine Templates",
+ "templates.description": "Capture templates define how the screen is captured. Each template uses a specific capture engine (MSS, DXcam, WGC) with custom settings. Assign templates to devices for optimal performance.",
+ "templates.loading": "Loading templates...",
+ "templates.empty": "No capture templates configured",
+ "templates.add": "Add Engine Template",
+ "templates.edit": "Edit Engine Template",
+ "templates.name": "Template Name:",
+ "templates.name.placeholder": "My Custom Template",
+ "templates.description.label": "Description (optional):",
+ "templates.description.placeholder": "Describe this template...",
+ "templates.engine": "Capture Engine:",
+ "templates.engine.hint": "Select the screen capture technology to use",
+ "templates.engine.select": "Select an engine...",
+ "templates.engine.unavailable": "Unavailable",
+ "templates.engine.unavailable.hint": "This engine is not available on your system",
+ "templates.engine.mss.desc": "Cross-platform, pure Python",
+ "templates.engine.dxcam.desc": "DirectX, low latency",
+ "templates.engine.bettercam.desc": "DirectX, high performance",
+ "templates.engine.camera.desc": "USB/IP camera capture",
+ "templates.engine.scrcpy.desc": "Android screen mirror",
+ "templates.engine.wgc.desc": "Windows Graphics Capture",
+ "templates.config": "Configuration",
+ "templates.config.show": "Show configuration",
+ "templates.config.none": "No additional configuration",
+ "templates.config.default": "Default",
+ "templates.config.camera_backend.auto": "Auto-detect best backend",
+ "templates.config.camera_backend.dshow": "Windows DirectShow",
+ "templates.config.camera_backend.msmf": "Windows Media Foundation",
+ "templates.config.camera_backend.v4l2": "Linux Video4Linux2",
+ "templates.created": "Template created successfully",
+ "templates.updated": "Template updated successfully",
+ "templates.deleted": "Template deleted successfully",
+ "templates.delete.confirm": "Are you sure you want to delete this template?",
+ "templates.error.load": "Failed to load templates",
+ "templates.error.engines": "Failed to load engines",
+ "templates.error.required": "Please fill in all required fields",
+ "templates.error.delete": "Failed to delete template",
+ "templates.test.title": "Test Capture",
+ "templates.test.description": "Test this template before saving to see a capture preview and performance metrics.",
+ "templates.test.display": "Display:",
+ "templates.test.display.select": "Select display...",
+ "templates.test.duration": "Capture Duration (s):",
+ "templates.test.border_width": "Border Width (px):",
+ "templates.test.run": "Run",
+ "templates.test.running": "Running test...",
+ "templates.test.results.preview": "Full Capture Preview",
+ "templates.test.results.borders": "Border Extraction",
+ "templates.test.results.top": "Top",
+ "templates.test.results.right": "Right",
+ "templates.test.results.bottom": "Bottom",
+ "templates.test.results.left": "Left",
+ "templates.test.results.performance": "Performance",
+ "templates.test.results.capture_time": "Capture",
+ "templates.test.results.extraction_time": "Extraction",
+ "templates.test.results.total_time": "Total",
+ "templates.test.results.max_fps": "Max FPS",
+ "templates.test.results.duration": "Duration",
+ "templates.test.results.frame_count": "Frames",
+ "templates.test.results.actual_fps": "Actual FPS",
+ "templates.test.results.avg_capture_time": "Avg Capture",
+ "templates.test.results.resolution": "Resolution:",
+ "templates.test.error.no_engine": "Please select a capture engine",
+ "templates.test.error.no_display": "Please select a display",
+ "templates.test.error.failed": "Test failed",
+ "devices.title": "Devices",
+ "device.select_type": "Select Device Type",
+ "devices.add": "Add New Device",
+ "devices.loading": "Loading devices...",
+ "devices.none": "No devices configured",
+ "devices.failed": "Failed to load devices",
+ "devices.wled_config": "WLED Configuration:",
+ "devices.wled_note": "Configure your WLED device (effects, segments, color order, power limits, etc.) using the",
+ "devices.wled_link": "official WLED app",
+ "devices.wled_note_or": "or the built-in",
+ "devices.wled_webui_link": "WLED Web UI",
+ "devices.wled_note_webui": "(open your device's IP in a browser).",
+ "devices.wled_note2": "This controller sends pixel color data and controls brightness per device.",
+ "device.scan": "Auto Discovery",
+ "device.scan.empty": "No devices found",
+ "device.scan.error": "Network scan failed",
+ "device.scan.already_added": "Already added",
+ "device.scan.selected": "Device selected",
+ "device.type": "Device Type:",
+ "device.type.hint": "Select the type of LED controller",
+ "device.type.wled": "WLED",
+ "device.type.wled.desc": "WiFi LED controller over HTTP/UDP",
+ "device.type.adalight": "Adalight",
+ "device.type.adalight.desc": "Serial LED protocol for Arduino",
+ "device.type.ambiled": "AmbiLED",
+ "device.type.ambiled.desc": "Serial protocol for AmbiLED devices",
+ "device.type.mqtt": "MQTT",
+ "device.type.mqtt.desc": "Publish LED data via MQTT broker",
+ "device.type.ws": "WebSocket",
+ "device.type.ws.desc": "Stream LED data to WebSocket clients",
+ "device.type.openrgb": "OpenRGB",
+ "device.type.openrgb.desc": "Control RGB peripherals via OpenRGB",
+ "device.type.dmx": "DMX",
+ "device.type.dmx.desc": "Art-Net / sACN (E1.31) stage lighting",
+ "device.type.mock": "Mock",
+ "device.type.mock.desc": "Virtual device for testing",
+ "device.type.espnow": "ESP-NOW",
+ "device.type.espnow.desc": "Ultra-low-latency via ESP32 gateway",
+ "device.type.hue": "Philips Hue",
+ "device.type.hue.desc": "Hue Entertainment API streaming",
+ "device.type.usbhid": "USB HID",
+ "device.type.usbhid.desc": "USB RGB peripherals (keyboards, mice)",
+ "device.type.spi": "SPI Direct",
+ "device.type.spi.desc": "Raspberry Pi GPIO/SPI LED strips",
+ "device.type.chroma": "Razer Chroma",
+ "device.type.chroma.desc": "Razer peripherals via Chroma SDK",
+ "device.type.gamesense": "SteelSeries",
+ "device.type.gamesense.desc": "SteelSeries peripherals via GameSense",
+ "device.chroma.device_type": "Peripheral Type:",
+ "device.chroma.device_type.hint": "Which Razer peripheral to control via Chroma SDK",
+ "device.gamesense.device_type": "Peripheral Type:",
+ "device.gamesense.device_type.hint": "Which SteelSeries peripheral to control via GameSense",
+ "device.espnow.peer_mac": "Peer MAC:",
+ "device.espnow.peer_mac.hint": "MAC address of the remote ESP32 receiver (e.g. AA:BB:CC:DD:EE:FF)",
+ "device.espnow.channel": "WiFi Channel:",
+ "device.espnow.channel.hint": "WiFi channel (1-14). Must match the receiver's channel.",
+ "device.hue.url": "Bridge IP:",
+ "device.hue.url.hint": "IP address of your Hue bridge",
+ "device.hue.username": "Bridge Username:",
+ "device.hue.username.hint": "Hue bridge application key from pairing",
+ "device.hue.client_key": "Client Key:",
+ "device.hue.client_key.hint": "Entertainment API client key (hex string from pairing)",
+ "device.hue.group_id": "Entertainment Group:",
+ "device.hue.group_id.hint": "Entertainment configuration ID from your Hue bridge",
+ "device.usbhid.url": "VID:PID:",
+ "device.usbhid.url.hint": "USB Vendor:Product ID in hex (e.g. 1532:0084)",
+ "device.spi.url": "GPIO/SPI Path:",
+ "device.spi.url.hint": "GPIO pin or SPI device path (e.g. spi://gpio:18)",
+ "device.spi.speed": "SPI Speed (Hz):",
+ "device.spi.speed.hint": "SPI clock speed. 800000 Hz for WS2812, 2400000 Hz for APA102.",
+ "device.spi.led_type": "LED Chipset:",
+ "device.spi.led_type.hint": "Type of addressable LED strip connected to the GPIO/SPI pin",
+ "device.spi.led_type.ws2812b.desc": "Most common, 800 KHz data, 3-wire RGB",
+ "device.spi.led_type.ws2812.desc": "Original WS2812, 800 KHz, 3-wire RGB",
+ "device.spi.led_type.ws2811.desc": "External driver IC, 400 KHz, 12V strips",
+ "device.spi.led_type.sk6812.desc": "Samsung LED, 800 KHz, 3-wire RGB",
+ "device.spi.led_type.sk6812_rgbw.desc": "SK6812 with dedicated white channel",
+ "device.gamesense.peripheral.keyboard": "Keyboard",
+ "device.gamesense.peripheral.keyboard.desc": "Per-key RGB illumination",
+ "device.gamesense.peripheral.mouse": "Mouse",
+ "device.gamesense.peripheral.mouse.desc": "Mouse RGB zones",
+ "device.gamesense.peripheral.headset": "Headset",
+ "device.gamesense.peripheral.headset.desc": "Headset earcup lighting",
+ "device.gamesense.peripheral.mousepad": "Mousepad",
+ "device.gamesense.peripheral.mousepad.desc": "Mousepad edge lighting zones",
+ "device.gamesense.peripheral.indicator": "Indicator",
+ "device.gamesense.peripheral.indicator.desc": "OLED/LED status indicator",
+ "device.css_processing_template": "Strip Processing Template:",
+ "device.css_processing_template.hint": "Default processing template applied to all color strip outputs on this device",
+ "device.dmx_protocol": "DMX Protocol:",
+ "device.dmx_protocol.hint": "Art-Net uses UDP port 6454, sACN (E1.31) uses UDP port 5568",
+ "device.dmx_protocol.artnet.desc": "UDP unicast, port 6454",
+ "device.dmx_protocol.sacn.desc": "Multicast/unicast, port 5568",
+ "device.dmx_start_universe": "Start Universe:",
+ "device.dmx_start_universe.hint": "First DMX universe (0-32767). Multiple universes are used automatically for >170 LEDs.",
+ "device.dmx_start_channel": "Start Channel:",
+ "device.dmx_start_channel.hint": "First DMX channel within the universe (1-512)",
+ "device.dmx.url": "IP Address:",
+ "device.dmx.url.hint": "IP address of the DMX node (e.g. 192.168.1.50)",
+ "device.dmx.url.placeholder": "192.168.1.50",
+ "device.serial_port": "Serial Port:",
+ "device.serial_port.hint": "Select the COM port of the Adalight device",
+ "device.serial_port.none": "No serial ports found",
+ "device.serial_port.select": "Select a port...",
+ "device.led_count_manual.hint": "Number of LEDs on the strip (must match your Arduino sketch)",
+ "device.baud_rate": "Baud Rate:",
+ "device.baud_rate.hint": "Serial communication speed. Higher = more FPS but requires matching Arduino sketch.",
+ "device.led_type": "LED Type:",
+ "device.led_type.hint": "RGB (3 channels) or RGBW (4 channels with dedicated white)",
+ "device.send_latency": "Send Latency (ms):",
+ "device.send_latency.hint": "Simulated network/serial delay per frame in milliseconds",
+ "device.mqtt_topic": "MQTT Topic:",
+ "device.mqtt_topic.hint": "MQTT topic path for publishing pixel data (e.g. mqtt://ledgrab/device/name)",
+ "device.mqtt_topic.placeholder": "mqtt://ledgrab/device/living-room",
+ "device.ws_url": "Connection URL:",
+ "device.ws_url.hint": "WebSocket URL for clients to connect and receive LED data",
+ "device.openrgb.url": "OpenRGB URL:",
+ "device.openrgb.url.hint": "OpenRGB server address (e.g. openrgb://localhost:6742/0)",
+ "device.openrgb.zone": "Zones:",
+ "device.openrgb.zone.hint": "Select which LED zones to control (leave all unchecked for all zones)",
+ "device.openrgb.zone.loading": "Loading zones…",
+ "device.openrgb.zone.error": "Failed to load zones",
+ "device.openrgb.mode": "Zone mode:",
+ "device.openrgb.mode.hint": "Combined treats all zones as one continuous LED strip. Separate renders each zone independently with the full effect.",
+ "device.openrgb.mode.combined": "Combined strip",
+ "device.openrgb.mode.separate": "Independent zones",
+ "device.openrgb.added_multiple": "Added {count} devices",
+ "device.url.hint": "IP address or hostname of the device (e.g. http://192.168.1.100)",
+ "device.name": "Device Name:",
+ "device.name.placeholder": "Living Room TV",
+ "device.url": "URL:",
+ "device.url.placeholder": "http://192.168.1.100",
+ "device.led_count": "LED Count:",
+ "device.led_count.hint": "Number of LEDs configured in the device",
+ "device.led_count.hint.auto": "Auto-detected from device",
+ "device.button.add": "Add Device",
+ "device.button.start": "Start",
+ "device.button.stop": "Stop",
+ "device.button.settings": "General Settings",
+ "device.button.capture_settings": "Capture Settings",
+ "device.button.calibrate": "Calibrate",
+ "device.button.remove": "Remove",
+ "device.button.webui": "Open Device Web UI",
+ "device.button.power_off": "Turn Off",
+ "device.button.ping": "Ping Device",
+ "device.ping.online": "Online ({ms}ms)",
+ "device.ping.offline": "Device offline",
+ "device.ping.error": "Ping failed",
+ "device.power.off_success": "Device turned off",
+ "device.status.connected": "Connected",
+ "device.status.disconnected": "Disconnected",
+ "device.status.error": "Error",
+ "device.status.processing": "Processing",
+ "device.status.idle": "Idle",
+ "device.fps": "FPS:",
+ "device.display": "Display:",
+ "device.remove.confirm": "Are you sure you want to remove this device?",
+ "device.added": "Device added successfully",
+ "device.removed": "Device removed",
+ "device.started": "Processing started",
+ "device.stopped": "Processing stopped",
+ "device.metrics.actual_fps": "Actual FPS",
+ "device.metrics.current_fps": "Current FPS",
+ "device.metrics.target_fps": "Target FPS",
+ "device.metrics.potential_fps": "Potential FPS",
+ "device.metrics.frames": "Frames",
+ "device.metrics.frames_skipped": "Skipped",
+ "device.metrics.keepalive": "Keepalive",
+ "device.metrics.errors": "Errors",
+ "device.metrics.uptime": "Uptime",
+ "device.metrics.timing": "Pipeline timing:",
+ "device.metrics.device_fps": "Device refresh rate",
+ "device.health.online": "Online",
+ "device.health.offline": "Offline",
+ "device.health.streaming_unreachable": "Unreachable during streaming",
+ "device.health.checking": "Checking...",
+ "device.last_seen.label": "Last seen",
+ "device.last_seen.just_now": "just now",
+ "device.last_seen.seconds": "%ds ago",
+ "device.last_seen.minutes": "%dm ago",
+ "device.last_seen.hours": "%dh ago",
+ "device.last_seen.days": "%dd ago",
+ "device.tutorial.start": "Start tutorial",
+ "device.tip.metadata": "Device info (LED count, type, color channels) is auto-detected from the device",
+ "device.tip.brightness": "Slide to adjust device brightness",
+ "device.tip.start": "Start or stop screen capture processing",
+ "device.tip.settings": "Configure general device settings (name, URL, health check)",
+ "device.tip.capture_settings": "Configure capture settings (display, capture template)",
+ "device.tip.calibrate": "Calibrate LED positions, direction, and coverage",
+ "device.tip.webui": "Open the device's built-in web interface for advanced configuration",
+ "device.tip.add": "Click here to add a new LED device",
+ "settings.title": "Settings",
+ "settings.tab.general": "General",
+ "settings.tab.backup": "Backup",
+ "settings.tab.mqtt": "MQTT",
+ "settings.logs.open_viewer": "Open Log Viewer",
+ "settings.external_url.label": "External URL",
+ "settings.external_url.hint": "If set, this base URL is used in webhook URLs and other user-visible links instead of the auto-detected local IP. Example: https://myserver.example.com:8080",
+ "settings.external_url.placeholder": "https://myserver.example.com:8080",
+ "settings.external_url.save": "Save",
+ "settings.external_url.saved": "External URL saved",
+ "settings.external_url.save_error": "Failed to save external URL",
+ "settings.general.title": "General Settings",
+ "settings.capture.title": "Capture Settings",
+ "settings.capture.saved": "Capture settings updated",
+ "settings.capture.failed": "Failed to save capture settings",
+ "settings.brightness": "Brightness:",
+ "settings.brightness.hint": "Global brightness for this device (0-100%)",
+ "settings.url.hint": "IP address or hostname of the device",
+ "settings.display_index": "Display:",
+ "settings.display_index.hint": "Which screen to capture for this device",
+ "settings.fps": "Target FPS:",
+ "settings.fps.hint": "Target frames per second (10-90)",
+ "settings.capture_template": "Engine Template:",
+ "settings.capture_template.hint": "Screen capture engine and configuration for this device",
+ "settings.button.cancel": "Cancel",
+ "settings.health_interval": "Health Check Interval (s):",
+ "settings.health_interval.hint": "How often to check the device status (5-600 seconds)",
+ "settings.auto_shutdown": "Auto Restore:",
+ "settings.auto_shutdown.hint": "Restore device to idle state when targets stop or server shuts down",
+ "settings.button.save": "Save Changes",
+ "settings.saved": "Settings saved successfully",
+ "settings.failed": "Failed to save settings",
+ "calibration.title": "LED Calibration",
+ "calibration.tip.led_count": "Enter LED count per edge",
+ "calibration.tip.start_corner": "Click a corner to set the start position",
+ "calibration.tip.direction": "Toggle LED strip direction (clockwise / counterclockwise)",
+ "calibration.tip.offset": "Set LED offset — distance from LED 0 to the start corner",
+ "calibration.tip.span": "Drag green bars to adjust coverage span",
+ "calibration.tip.test": "Click an edge to toggle test LEDs",
+ "calibration.tip.overlay": "Toggle screen overlay to see LED positions and numbering on your monitor",
+ "calibration.tip.toggle_inputs": "Click total LED count to toggle edge inputs",
+ "calibration.tip.border_width": "How many pixels from the screen edge to sample for LED colors",
+ "calibration.tip.skip_leds_start": "Skip LEDs at the start of the strip — skipped LEDs stay off",
+ "calibration.tip.skip_leds_end": "Skip LEDs at the end of the strip — skipped LEDs stay off",
+ "tour.welcome": "Welcome to LED Grab! This quick tour will show you around the interface. Use arrow keys or buttons to navigate.",
+ "tour.dashboard": "Dashboard — live overview of running targets, automations, and device health at a glance.",
+ "tour.targets": "Targets — add WLED devices, configure LED targets with capture settings and calibration.",
+ "tour.sources": "Sources — manage capture templates, picture sources, audio sources, and color strips.",
+ "tour.graph": "Graph — visual overview of all entities and their connections. Drag ports to connect, right-click edges to disconnect.",
+ "tour.automations": "Automations — automate scene switching with time, audio, or value conditions.",
+ "tour.settings": "Settings — backup and restore configuration, manage auto-backups.",
+ "tour.api": "API Docs — interactive REST API documentation powered by Swagger.",
+ "tour.search": "Search — quickly find and navigate to any entity with Ctrl+K.",
+ "tour.theme": "Theme — switch between dark and light mode.",
+ "tour.accent": "Accent color — customize the UI accent color to your preference.",
+ "tour.language": "Language — choose your preferred interface language.",
+ "tour.restart": "Restart tutorial",
+ "tour.dash.perf": "Performance — real-time FPS charts, latency metrics, and poll interval control.",
+ "tour.dash.running": "Running targets — live streaming metrics and quick stop control.",
+ "tour.dash.stopped": "Stopped targets — ready to start with one click.",
+ "tour.dash.automations": "Automations — active automation status and quick enable/disable toggle.",
+ "tour.tgt.led_tab": "LED tab — standard LED strip targets with device and color strip configuration.",
+ "tour.tgt.devices": "Devices — your LED controllers discovered on the network.",
+ "tour.tgt.css": "Color Strips — define how screen regions map to LED segments.",
+ "tour.tgt.targets": "LED Targets — combine a device, color strip, and capture source for streaming.",
+ "tour.tgt.kc_tab": "Key Colors — alternative target type using color-matching instead of pixel mapping.",
+ "tour.src.raw": "Raw — live screen capture sources from your displays.",
+ "tour.src.templates": "Capture Templates — reusable capture configurations (resolution, FPS, crop).",
+ "tour.src.static": "Static Image — test your setup with image files instead of live capture.",
+ "tour.src.processed": "Processed — apply post-processing effects like blur, brightness, or color correction.",
+ "tour.src.color_strip": "Color Strips — define how screen regions map to LED segments.",
+ "tour.src.audio": "Audio — analyze microphone or system audio for reactive LED effects.",
+ "tour.src.value": "Value — numeric data sources used as conditions in automations.",
+ "tour.src.sync": "Sync Clocks — shared timers that synchronize animations across multiple sources.",
+ "tour.auto.list": "Automations — automate scene activation based on time, audio, or value conditions.",
+ "tour.auto.add": "Click + to create a new automation with conditions and a scene to activate.",
+ "tour.auto.card": "Each card shows automation status, conditions, and quick controls to edit or toggle.",
+ "tour.auto.scenes_list": "Scenes — saved system states that automations can activate or you can apply manually.",
+ "tour.auto.scenes_add": "Click + to capture the current system state as a new scene preset.",
+ "tour.auto.scenes_card": "Each scene card shows target/device counts. Click to edit, recapture, or activate.",
+ "calibration.tutorial.start": "Start tutorial",
+ "calibration.overlay_toggle": "Overlay",
+ "calibration.start_position": "Starting Position:",
+ "calibration.position.bottom_left": "Bottom Left",
+ "calibration.position.bottom_right": "Bottom Right",
+ "calibration.position.top_left": "Top Left",
+ "calibration.position.top_right": "Top Right",
+ "calibration.direction": "Direction:",
+ "calibration.direction.clockwise": "Clockwise",
+ "calibration.direction.counterclockwise": "Counterclockwise",
+ "calibration.leds.top": "Top LEDs:",
+ "calibration.leds.right": "Right LEDs:",
+ "calibration.leds.bottom": "Bottom LEDs:",
+ "calibration.leds.left": "Left LEDs:",
+ "calibration.offset": "LED Offset:",
+ "calibration.offset.hint": "Distance from physical LED 0 to the start corner (along strip direction)",
+ "calibration.skip_start": "Skip LEDs (Start):",
+ "calibration.skip_start.hint": "Number of LEDs to turn off at the beginning of the strip (0 = none)",
+ "calibration.skip_end": "Skip LEDs (End):",
+ "calibration.skip_end.hint": "Number of LEDs to turn off at the end of the strip (0 = none)",
+ "calibration.border_width": "Border (px):",
+ "calibration.border_width.hint": "How many pixels from the screen edge to sample for LED colors (1-100)",
+ "calibration.button.cancel": "Cancel",
+ "calibration.button.save": "Save",
+ "calibration.saved": "Calibration saved",
+ "calibration.failed": "Failed to save calibration",
+ "server.healthy": "Server online",
+ "server.offline": "Server offline",
+ "error.unauthorized": "Unauthorized - please login",
+ "error.network": "Network error",
+ "error.unknown": "An error occurred",
+ "modal.discard_changes": "You have unsaved changes. Discard them?",
+ "confirm.title": "Confirm Action",
+ "confirm.yes": "Yes",
+ "confirm.no": "No",
+ "confirm.stop_all": "Stop all running targets?",
+ "confirm.turn_off_device": "Turn off this device?",
+ "common.loading": "Loading...",
+ "common.delete": "Delete",
+ "common.edit": "Edit",
+ "common.clone": "Clone",
+ "common.none": "None",
+ "common.none_no_cspt": "None (no processing template)",
+ "common.none_no_input": "None (no input source)",
+ "common.none_own_speed": "None (use own speed)",
+ "common.undo": "Undo",
+ "validation.required": "This field is required",
+ "bulk.processing": "Processing…",
+ "api.error.timeout": "Request timed out — please try again",
+ "api.error.network": "Network error — check your connection",
+ "palette.search": "Search…",
+ "section.filter.placeholder": "Filter...",
+ "section.filter.reset": "Clear filter",
+ "tags.label": "Tags",
+ "tags.hint": "Assign tags for grouping and filtering cards",
+ "tags.placeholder": "Add tag...",
+ "section.expand_all": "Expand all sections",
+ "section.collapse_all": "Collapse all sections",
+ "streams.title": "Sources",
+ "streams.description": "Sources define the capture pipeline. A raw source captures from a display using a capture template. A processed source applies postprocessing to another source. Assign sources to devices.",
+ "streams.group.raw": "Sources",
+ "streams.group.raw_templates": "Engine Templates",
+ "streams.group.processed": "Sources",
+ "streams.group.proc_templates": "Filter Templates",
+ "streams.group.css_processing": "Processing Templates",
+ "streams.group.color_strip": "Color Strips",
+ "streams.group.audio": "Audio",
+ "streams.group.audio_templates": "Audio Templates",
+ "streams.section.streams": "Sources",
+ "streams.add": "Add Source",
+ "streams.add.raw": "Add Screen Capture",
+ "streams.add.processed": "Add Processed Source",
+ "streams.edit": "Edit Source",
+ "streams.edit.raw": "Edit Screen Capture",
+ "streams.edit.processed": "Edit Processed Source",
+ "streams.name": "Source Name:",
+ "streams.name.placeholder": "My Source",
+ "streams.type": "Type:",
+ "streams.type.raw": "Screen Capture",
+ "streams.type.processed": "Processed",
+ "streams.display": "Display:",
+ "streams.display.hint": "Which screen to capture",
+ "streams.capture_template": "Engine Template:",
+ "streams.capture_template.hint": "Engine template defining how the screen is captured",
+ "streams.target_fps": "Target FPS:",
+ "streams.target_fps.hint": "Target frames per second for capture (1-90)",
+ "streams.source": "Source:",
+ "streams.source.hint": "The source to apply processing filters to",
+ "streams.pp_template": "Filter Template:",
+ "streams.pp_template.hint": "Filter template to apply to the source",
+ "streams.description_label": "Description (optional):",
+ "streams.description_placeholder": "Describe this source...",
+ "streams.created": "Source created successfully",
+ "streams.updated": "Source updated successfully",
+ "streams.deleted": "Source deleted successfully",
+ "streams.delete.confirm": "Are you sure you want to delete this source?",
+ "streams.modal.loading": "Loading...",
+ "streams.error.load": "Failed to load sources",
+ "streams.error.required": "Please fill in all required fields",
+ "streams.error.delete": "Failed to delete source",
+ "streams.test.title": "Test Source",
+ "streams.test.run": "Run",
+ "streams.test.running": "Testing source...",
+ "streams.test.duration": "Capture Duration (s):",
+ "streams.test.error.failed": "Source test failed",
+ "postprocessing.title": "Filter Templates",
+ "postprocessing.description": "Processing templates define image filters and color correction. Assign them to processed picture sources for consistent postprocessing across devices.",
+ "postprocessing.add": "Add Filter Template",
+ "postprocessing.edit": "Edit Filter Template",
+ "postprocessing.name": "Template Name:",
+ "postprocessing.name.placeholder": "My Filter Template",
+ "filters.select_type": "Select filter type...",
+ "filters.add": "Add Filter",
+ "filters.remove": "Remove",
+ "filters.drag_to_reorder": "Drag to reorder",
+ "filters.empty": "No filters added. Use the selector below to add filters.",
+ "filters.brightness": "Brightness",
+ "filters.brightness.desc": "Adjust overall image brightness",
+ "filters.saturation": "Saturation",
+ "filters.saturation.desc": "Boost or reduce color intensity",
+ "filters.gamma": "Gamma",
+ "filters.gamma.desc": "Non-linear brightness curve correction",
+ "filters.downscaler": "Downscaler",
+ "filters.downscaler.desc": "Reduce resolution for faster processing",
+ "filters.pixelate": "Pixelate",
+ "filters.pixelate.desc": "Mosaic-style block averaging",
+ "filters.auto_crop": "Auto Crop",
+ "filters.auto_crop.desc": "Remove black bars from letterboxed content",
+ "filters.flip": "Flip",
+ "filters.flip.desc": "Mirror image horizontally or vertically",
+ "filters.color_correction": "Color Correction",
+ "filters.color_correction.desc": "White balance and color temperature",
+ "filters.filter_template": "Filter Template",
+ "filters.filter_template.desc": "Embed another processing template",
+ "filters.css_filter_template": "Strip Filter Template",
+ "filters.css_filter_template.desc": "Embed another strip processing template",
+ "filters.frame_interpolation": "Frame Interpolation",
+ "filters.frame_interpolation.desc": "Blend between frames for smoother output",
+ "filters.noise_gate": "Noise Gate",
+ "filters.noise_gate.desc": "Suppress small color changes below threshold",
+ "filters.palette_quantization": "Palette Quantization",
+ "filters.palette_quantization.desc": "Reduce colors to a limited palette",
+ "filters.reverse": "Reverse",
+ "filters.reverse.desc": "Reverse the LED order in the strip",
+ "postprocessing.description_label": "Description (optional):",
+ "postprocessing.description_placeholder": "Describe this template...",
+ "postprocessing.created": "Template created successfully",
+ "postprocessing.updated": "Template updated successfully",
+ "postprocessing.deleted": "Template deleted successfully",
+ "postprocessing.delete.confirm": "Are you sure you want to delete this filter template?",
+ "postprocessing.error.load": "Failed to load processing templates",
+ "postprocessing.error.required": "Please fill in all required fields",
+ "postprocessing.error.delete": "Failed to delete processing template",
+ "postprocessing.config.show": "Show settings",
+ "postprocessing.test.title": "Test Filter Template",
+ "postprocessing.test.source_stream": "Source:",
+ "postprocessing.test.running": "Testing processing template...",
+ "postprocessing.test.error.no_stream": "Please select a source",
+ "postprocessing.test.error.failed": "Processing template test failed",
+ "css_processing.title": "Strip Processing Templates",
+ "css_processing.add": "Add Strip Processing Template",
+ "css_processing.edit": "Edit Strip Processing Template",
+ "css_processing.name": "Template Name:",
+ "css_processing.name_placeholder": "My Strip Processing Template",
+ "css_processing.description_label": "Description (optional):",
+ "css_processing.description_placeholder": "Describe this template...",
+ "css_processing.created": "Strip processing template created",
+ "css_processing.updated": "Strip processing template updated",
+ "css_processing.deleted": "Strip processing template deleted",
+ "css_processing.delete.confirm": "Are you sure you want to delete this strip processing template?",
+ "css_processing.error.required": "Please fill in all required fields",
+ "css_processing.error.load": "Error loading strip processing template",
+ "css_processing.error.delete": "Error deleting strip processing template",
+ "css_processing.error.clone_failed": "Failed to clone strip processing template",
+ "device.button.stream_selector": "Source Settings",
+ "device.stream_settings.title": "Source Settings",
+ "device.stream_selector.label": "Source:",
+ "device.stream_selector.hint": "Select a source that defines what this device captures and processes",
+ "device.stream_selector.none": "-- No source assigned --",
+ "device.stream_selector.saved": "Source settings updated",
+ "device.stream_settings.border_width": "Border Width (px):",
+ "device.stream_settings.border_width_hint": "How many pixels from the screen edge to sample for LED colors (1-100)",
+ "device.stream_settings.interpolation": "Interpolation Mode:",
+ "device.stream_settings.interpolation.average": "Average",
+ "device.stream_settings.interpolation.median": "Median",
+ "device.stream_settings.interpolation.dominant": "Dominant",
+ "device.stream_settings.interpolation_hint": "How to calculate LED color from sampled pixels",
+ "device.stream_settings.smoothing": "Smoothing:",
+ "device.stream_settings.smoothing_hint": "Temporal blending between frames (0=none, 1=full). Reduces flicker.",
+ "device.tip.stream_selector": "Configure picture source and LED projection settings for this device",
+ "streams.group.static_image": "Static Image",
+ "streams.add.static_image": "Add Static Image Source",
+ "streams.edit.static_image": "Edit Static Image Source",
+ "streams.type.static_image": "Static Image",
+ "streams.group.video": "Video",
+ "streams.add.video": "Add Video Source",
+ "streams.edit.video": "Edit Video Source",
+ "picture_source.type.video": "Video",
+ "picture_source.type.video.desc": "Stream frames from video file, URL, or YouTube",
+ "picture_source.video.url": "Video URL:",
+ "picture_source.video.url.hint": "Local file path, HTTP URL, or YouTube URL",
+ "picture_source.video.url.placeholder": "https://example.com/video.mp4",
+ "picture_source.video.loop": "Loop:",
+ "picture_source.video.speed": "Playback Speed:",
+ "picture_source.video.start_time": "Start Time (s):",
+ "picture_source.video.end_time": "End Time (s):",
+ "picture_source.video.resolution_limit": "Max Width (px):",
+ "picture_source.video.resolution_limit.hint": "Downscale video at decode time for performance",
+ "streams.image_source": "Image Source:",
+ "streams.image_source.placeholder": "https://example.com/image.jpg or C:\\path\\to\\image.png",
+ "streams.image_source.hint": "Enter a URL (http/https) or local file path to an image",
+ "streams.validate_image.validating": "Validating...",
+ "streams.validate_image.valid": "Image accessible",
+ "streams.validate_image.invalid": "Image not accessible",
+ "targets.title": "Targets",
+ "targets.description": "Targets bridge color strip sources to output devices. Each target references a device and a color strip source.",
+ "targets.subtab.wled": "LED",
+ "targets.subtab.led": "LED",
+ "targets.section.devices": "Devices",
+ "targets.section.color_strips": "Color Strip Sources",
+ "targets.section.targets": "Targets",
+ "targets.section.specific_settings": "Specific Settings",
+ "targets.section.advanced": "Advanced",
+ "targets.add": "Add Target",
+ "targets.edit": "Edit Target",
+ "targets.loading": "Loading targets...",
+ "targets.none": "No targets configured",
+ "targets.failed": "Failed to load targets",
+ "targets.name": "Target Name:",
+ "targets.name.placeholder": "My Target",
+ "targets.device": "Device:",
+ "targets.device.hint": "Select the LED device to send data to",
+ "targets.device.none": "-- Select a device --",
+ "targets.color_strip_source": "Color Strip Source:",
+ "targets.color_strip_source.hint": "Select the color strip source that provides LED colors for this target",
+ "targets.no_css": "No source",
+ "targets.source": "Source:",
+ "targets.source.hint": "Which picture source to capture and process",
+ "targets.source.none": "-- No source assigned --",
+ "targets.metrics.pipeline": "Pipeline details",
+ "targets.fps": "Target FPS:",
+ "targets.fps.hint": "Target frames per second for capture and LED updates (1-90)",
+ "targets.fps.rec": "Hardware max ≈ {fps} fps ({leds} LEDs)",
+ "targets.border_width": "Border Width (px):",
+ "targets.border_width.hint": "How many pixels from the screen edge to sample for LED colors (1-100)",
+ "targets.interpolation": "Interpolation Mode:",
+ "targets.interpolation.hint": "How to calculate LED color from sampled pixels",
+ "targets.interpolation.average": "Average",
+ "targets.interpolation.median": "Median",
+ "targets.interpolation.dominant": "Dominant",
+ "targets.smoothing": "Smoothing:",
+ "targets.smoothing.hint": "Temporal blending between frames (0=none, 1=full). Reduces flicker.",
+ "targets.keepalive_interval": "Keep Alive Interval:",
+ "targets.keepalive_interval.hint": "How often to resend the last frame when the source is static, keeping the device in live mode (0.5-5.0s)",
+ "targets.created": "Target created successfully",
+ "targets.updated": "Target updated successfully",
+ "targets.deleted": "Target deleted successfully",
+ "targets.delete.confirm": "Are you sure you want to delete this target?",
+ "targets.error.load": "Failed to load targets",
+ "targets.error.required": "Please fill in all required fields",
+ "targets.error.name_required": "Please enter a target name",
+ "targets.error.delete": "Failed to delete target",
+ "targets.button.start": "Start",
+ "targets.button.stop": "Stop",
+ "targets.status.processing": "Processing",
+ "targets.status.idle": "Idle",
+ "targets.status.error": "Error",
+ "targets.metrics.actual_fps": "Actual FPS",
+ "targets.metrics.target_fps": "Target FPS",
+ "targets.metrics.frames": "Frames",
+ "targets.metrics.errors": "Errors",
+ "targets.subtab.key_colors": "Key Colors",
+ "targets.section.key_colors": "Key Colors Targets",
+ "kc.add": "Add Key Colors Target",
+ "kc.edit": "Edit Key Colors Target",
+ "kc.name": "Target Name:",
+ "kc.name.placeholder": "My Key Colors Target",
+ "kc.source": "Picture Source:",
+ "kc.source.hint": "Which picture source to extract colors from",
+ "kc.source.none": "-- No source assigned --",
+ "kc.fps": "Extraction FPS:",
+ "kc.fps.hint": "How many times per second to extract colors (1-60)",
+ "kc.interpolation": "Color Mode:",
+ "kc.interpolation.hint": "How to compute the key color from pixels in each rectangle",
+ "kc.interpolation.average": "Average",
+ "kc.interpolation.median": "Median",
+ "kc.interpolation.dominant": "Dominant",
+ "kc.interpolation.average.desc": "Mean of all pixel colors",
+ "kc.interpolation.median.desc": "Middle color value per channel",
+ "kc.interpolation.dominant.desc": "Most frequent color",
+ "kc.smoothing": "Smoothing:",
+ "kc.smoothing.hint": "Temporal blending between extractions (0=none, 1=full)",
+ "kc.pattern_template": "Pattern Template:",
+ "kc.pattern_template.hint": "Select the rectangle pattern to use for color extraction",
+ "kc.pattern_template.none": "-- Select a pattern template --",
+ "kc.brightness_vs": "Brightness Source:",
+ "kc.brightness_vs.hint": "Optional value source that dynamically controls brightness each frame (multiplied with the manual brightness slider)",
+ "kc.brightness_vs.none": "None (manual brightness only)",
+ "kc.created": "Key colors target created successfully",
+ "kc.updated": "Key colors target updated successfully",
+ "kc.deleted": "Key colors target deleted successfully",
+ "kc.delete.confirm": "Are you sure you want to delete this key colors target?",
+ "kc.error.no_pattern": "Please select a pattern template",
+ "kc.error.required": "Please fill in all required fields",
+ "kc.colors.none": "No colors extracted yet",
+ "kc.test": "Test",
+ "kc.test.error": "Test failed",
+ "targets.section.pattern_templates": "Pattern Templates",
+ "pattern.add": "Add Pattern Template",
+ "pattern.edit": "Edit Pattern Template",
+ "pattern.name": "Template Name:",
+ "pattern.name.placeholder": "My Pattern Template",
+ "pattern.description_label": "Description (optional):",
+ "pattern.description_placeholder": "Describe this pattern...",
+ "pattern.rectangles": "Rectangles",
+ "pattern.rect.name": "Name",
+ "pattern.rect.x": "X",
+ "pattern.rect.y": "Y",
+ "pattern.rect.width": "W",
+ "pattern.rect.height": "H",
+ "pattern.rect.add": "Add Rectangle",
+ "pattern.rect.remove": "Remove",
+ "pattern.rect.empty": "No rectangles defined. Add at least one rectangle.",
+ "pattern.created": "Pattern template created successfully",
+ "pattern.updated": "Pattern template updated successfully",
+ "pattern.deleted": "Pattern template deleted successfully",
+ "pattern.delete.confirm": "Are you sure you want to delete this pattern template?",
+ "pattern.delete.referenced": "Cannot delete: this template is referenced by a target",
+ "pattern.error.required": "Please fill in all required fields",
+ "pattern.visual_editor": "Visual Editor",
+ "pattern.capture_bg": "Capture Background",
+ "pattern.source_for_bg": "Source for Background:",
+ "pattern.source_for_bg.none": "-- Select source --",
+ "pattern.delete_selected": "Delete Selected",
+ "pattern.name.hint": "A descriptive name for this rectangle layout",
+ "pattern.description.hint": "Optional notes about where or how this pattern is used",
+ "pattern.visual_editor.hint": "Click + buttons to add rectangles. Drag edges to resize, drag inside to move.",
+ "pattern.rectangles.hint": "Fine-tune rectangle positions and sizes with exact coordinates (0.0 to 1.0)",
+ "overlay.toggle": "Toggle screen overlay",
+ "overlay.button.show": "Show overlay visualization",
+ "overlay.button.hide": "Hide overlay visualization",
+ "overlay.started": "Overlay visualization started",
+ "overlay.stopped": "Overlay visualization stopped",
+ "overlay.error.start": "Failed to start overlay",
+ "overlay.error.stop": "Failed to stop overlay",
+ "dashboard.title": "Dashboard",
+ "dashboard.section.targets": "Targets",
+ "dashboard.section.running": "Running",
+ "dashboard.section.stopped": "Stopped",
+ "dashboard.no_targets": "No targets configured",
+ "dashboard.uptime": "Uptime",
+ "dashboard.fps": "FPS",
+ "dashboard.errors": "Errors",
+ "dashboard.device": "Device",
+ "dashboard.stop_all": "Stop All",
+ "dashboard.failed": "Failed to load dashboard",
+ "dashboard.section.automations": "Automations",
+ "dashboard.section.scenes": "Scene Presets",
+ "dashboard.section.sync_clocks": "Sync Clocks",
+ "dashboard.targets": "Targets",
+ "dashboard.section.performance": "System Performance",
+ "dashboard.perf.cpu": "CPU",
+ "dashboard.perf.ram": "RAM",
+ "dashboard.perf.gpu": "GPU",
+ "dashboard.perf.unavailable": "unavailable",
+ "dashboard.perf.color": "Chart color",
+ "dashboard.poll_interval": "Refresh interval",
+ "automations.title": "Automations",
+ "automations.empty": "No automations configured. Create one to automate scene activation.",
+ "automations.add": "Add Automation",
+ "automations.edit": "Edit Automation",
+ "automations.delete.confirm": "Delete automation \"{name}\"?",
+ "automations.name": "Name:",
+ "automations.name.hint": "A descriptive name for this automation",
+ "automations.name.placeholder": "My Automation",
+ "automations.enabled": "Enabled:",
+ "automations.enabled.hint": "Disabled automations won't activate even when conditions are met",
+ "automations.condition_logic": "Condition Logic:",
+ "automations.condition_logic.hint": "How multiple conditions are combined: ANY (OR) or ALL (AND)",
+ "automations.condition_logic.or": "Any condition (OR)",
+ "automations.condition_logic.and": "All conditions (AND)",
+ "automations.condition_logic.or.desc": "Triggers when any condition matches",
+ "automations.condition_logic.and.desc": "Triggers only when all match",
+ "automations.conditions": "Conditions:",
+ "automations.conditions.hint": "Rules that determine when this automation activates",
+ "automations.conditions.add": "Add Condition",
+ "automations.conditions.empty": "No conditions — automation is always active when enabled",
+ "automations.condition.always": "Always",
+ "automations.condition.always.desc": "Always active",
+ "automations.condition.always.hint": "Automation activates immediately when enabled and stays active.",
+ "automations.condition.startup": "Startup",
+ "automations.condition.startup.desc": "On server start",
+ "automations.condition.startup.hint": "Activates when the server starts and stays active while enabled.",
+ "automations.condition.application": "Application",
+ "automations.condition.application.desc": "App running/focused",
+ "automations.condition.application.apps": "Applications:",
+ "automations.condition.application.apps.hint": "Process names, one per line (e.g. firefox.exe)",
+ "automations.condition.application.browse": "Browse",
+ "automations.condition.application.search": "Filter processes...",
+ "automations.condition.application.no_processes": "No processes found",
+ "automations.condition.application.match_type": "Match Type:",
+ "automations.condition.application.match_type.hint": "How to detect the application",
+ "automations.condition.application.match_type.running": "Running",
+ "automations.condition.application.match_type.running.desc": "Process is active",
+ "automations.condition.application.match_type.topmost": "Topmost",
+ "automations.condition.application.match_type.topmost.desc": "Foreground window",
+ "automations.condition.application.match_type.topmost_fullscreen": "Topmost + FS",
+ "automations.condition.application.match_type.topmost_fullscreen.desc": "Foreground + fullscreen",
+ "automations.condition.application.match_type.fullscreen": "Fullscreen",
+ "automations.condition.application.match_type.fullscreen.desc": "Any fullscreen app",
+ "automations.condition.time_of_day": "Time of Day",
+ "automations.condition.time_of_day.desc": "Time range",
+ "automations.condition.time_of_day.start_time": "Start Time:",
+ "automations.condition.time_of_day.end_time": "End Time:",
+ "automations.condition.time_of_day.overnight_hint": "For overnight ranges (e.g. 22:00–06:00), set start time after end time.",
+ "automations.condition.system_idle": "System Idle",
+ "automations.condition.system_idle.desc": "User idle/active",
+ "automations.condition.system_idle.idle_minutes": "Idle Timeout (minutes):",
+ "automations.condition.system_idle.mode": "Trigger Mode:",
+ "automations.condition.system_idle.when_idle": "When idle",
+ "automations.condition.system_idle.when_active": "When active",
+ "automations.condition.display_state": "Display State",
+ "automations.condition.display_state.desc": "Monitor on/off",
+ "automations.condition.display_state.state": "Monitor State:",
+ "automations.condition.display_state.on": "On",
+ "automations.condition.display_state.off": "Off (sleeping)",
+ "automations.condition.mqtt": "MQTT",
+ "automations.condition.mqtt.desc": "MQTT message",
+ "automations.condition.mqtt.topic": "Topic:",
+ "automations.condition.mqtt.payload": "Payload:",
+ "automations.condition.mqtt.match_mode": "Match Mode:",
+ "automations.condition.mqtt.match_mode.exact": "Exact",
+ "automations.condition.mqtt.match_mode.contains": "Contains",
+ "automations.condition.mqtt.match_mode.regex": "Regex",
+ "automations.condition.mqtt.hint": "Activate when an MQTT topic receives a matching payload",
+ "automations.condition.webhook": "Webhook",
+ "automations.condition.webhook.desc": "HTTP callback",
+ "automations.condition.webhook.hint": "Activate via an HTTP call from external services (Home Assistant, IFTTT, curl, etc.)",
+ "automations.condition.webhook.url": "Webhook URL:",
+ "automations.condition.webhook.copy": "Copy",
+ "automations.condition.webhook.copied": "Copied!",
+ "automations.condition.webhook.save_first": "Save the automation first to generate a webhook URL",
+ "automations.scene": "Scene:",
+ "automations.scene.hint": "Scene preset to activate when conditions are met",
+ "automations.scene.search_placeholder": "Search scenes...",
+ "automations.scene.none_selected": "None (no scene)",
+ "automations.scene.none_available": "No scenes available",
+ "automations.deactivation_mode": "Deactivation:",
+ "automations.deactivation_mode.hint": "What happens when conditions stop matching",
+ "automations.deactivation_mode.none": "None",
+ "automations.deactivation_mode.none.desc": "Keep current state",
+ "automations.deactivation_mode.revert": "Revert",
+ "automations.deactivation_mode.revert.desc": "Restore previous state",
+ "automations.deactivation_mode.fallback_scene": "Fallback",
+ "automations.deactivation_mode.fallback_scene.desc": "Activate a fallback scene",
+ "automations.deactivation_scene": "Fallback Scene:",
+ "automations.deactivation_scene.hint": "Scene to activate when this automation deactivates",
+ "automations.status.active": "Active",
+ "automations.status.inactive": "Inactive",
+ "automations.status.disabled": "Disabled",
+ "automations.action.disable": "Disable",
+ "automations.last_activated": "Last activated",
+ "automations.logic.and": " AND ",
+ "automations.logic.or": " OR ",
+ "automations.logic.all": "ALL",
+ "automations.logic.any": "ANY",
+ "automations.updated": "Automation updated",
+ "automations.created": "Automation created",
+ "automations.deleted": "Automation deleted",
+ "automations.error.name_required": "Name is required",
+ "automations.error.clone_failed": "Failed to clone automation",
+ "scenes.title": "Scenes",
+ "scenes.add": "Capture Scene",
+ "scenes.edit": "Edit Scene",
+ "scenes.name": "Name:",
+ "scenes.name.hint": "A descriptive name for this scene preset",
+ "scenes.name.placeholder": "My Scene",
+ "scenes.description": "Description:",
+ "scenes.description.hint": "Optional description of what this scene does",
+ "scenes.targets": "Targets:",
+ "scenes.targets.hint": "Select which targets to include in this scene snapshot",
+ "scenes.targets.add": "Add Target",
+ "scenes.targets.search_placeholder": "Search targets...",
+ "scenes.capture": "Capture",
+ "scenes.activate": "Activate scene",
+ "scenes.recapture": "Recapture current state",
+ "scenes.delete": "Delete scene",
+ "scenes.targets_count": "targets",
+ "scenes.captured": "Scene captured",
+ "scenes.updated": "Scene updated",
+ "scenes.activated": "Scene activated",
+ "scenes.activated_partial": "Scene partially activated",
+ "scenes.errors": "errors",
+ "scenes.recaptured": "Scene recaptured",
+ "scenes.deleted": "Scene deleted",
+ "scenes.recapture_confirm": "Recapture current state into \"{name}\"?",
+ "scenes.delete_confirm": "Delete scene \"{name}\"?",
+ "scenes.error.name_required": "Name is required",
+ "scenes.error.save_failed": "Failed to save scene",
+ "scenes.error.activate_failed": "Failed to activate scene",
+ "scenes.error.recapture_failed": "Failed to recapture scene",
+ "scenes.error.delete_failed": "Failed to delete scene",
+ "scenes.cloned": "Scene cloned",
+ "scenes.error.clone_failed": "Failed to clone scene",
+ "time.hours_minutes": "{h}h {m}m",
+ "time.minutes_seconds": "{m}m {s}s",
+ "time.seconds": "{s}s",
+ "dashboard.type.led": "LED",
+ "dashboard.type.kc": "Key Colors",
+ "aria.close": "Close",
+ "aria.save": "Save",
+ "aria.cancel": "Cancel",
+ "aria.previous": "Previous",
+ "aria.next": "Next",
+ "aria.hint": "Show hint",
+ "color_strip.select_type": "Select Color Strip Type",
+ "color_strip.add": "Add Color Strip Source",
+ "color_strip.edit": "Edit Color Strip Source",
+ "color_strip.name": "Name:",
+ "color_strip.name.placeholder": "Wall Strip",
+ "color_strip.picture_source": "Picture Source:",
+ "color_strip.picture_source.hint": "Which screen capture source to use as input for LED color calculation",
+ "color_strip.fps": "Target FPS:",
+ "color_strip.fps.hint": "Target frames per second for LED color updates (10-90)",
+ "color_strip.interpolation": "Color Mode:",
+ "color_strip.interpolation.hint": "How to calculate LED color from sampled border pixels",
+ "color_strip.interpolation.average": "Average",
+ "color_strip.interpolation.median": "Median",
+ "color_strip.interpolation.dominant": "Dominant",
+ "color_strip.interpolation.average.desc": "Blend all sampled pixels into a smooth color",
+ "color_strip.interpolation.median.desc": "Pick the middle color, reducing outliers",
+ "color_strip.interpolation.dominant.desc": "Use the most frequent color in the sample",
+ "color_strip.smoothing": "Smoothing:",
+ "color_strip.smoothing.hint": "Temporal blending between frames (0=none, 1=full). Reduces flicker.",
+ "color_strip.frame_interpolation": "Frame Interpolation:",
+ "color_strip.frame_interpolation.hint": "Blends between consecutive captured frames to produce output at the full target FPS even when capture rate is lower. Reduces visible stepping on slow ambient transitions.",
+ "color_strip.color_corrections": "Color Corrections",
+ "color_strip.brightness": "Brightness:",
+ "color_strip.brightness.hint": "Output brightness multiplier (0=off, 1=unchanged, 2=double). Applied after color extraction.",
+ "color_strip.saturation": "Saturation:",
+ "color_strip.saturation.hint": "Color saturation (0=grayscale, 1=unchanged, 2=double saturation)",
+ "color_strip.gamma": "Gamma:",
+ "color_strip.gamma.hint": "Gamma correction (1=none, <1=brighter midtones, >1=darker midtones)",
+ "color_strip.test_device": "Test on Device:",
+ "color_strip.test_device.hint": "Select a device to send test pixels to when clicking edge toggles",
+ "color_strip.leds": "LED count",
+ "color_strip.led_count": "LED Count:",
+ "color_strip.led_count.hint": "Total number of LEDs on the physical strip. For screen sources: 0 = auto from calibration (extra LEDs not mapped to edges will be black). For static color: set to match your device LED count.",
+ "color_strip.created": "Color strip source created",
+ "color_strip.updated": "Color strip source updated",
+ "color_strip.deleted": "Color strip source deleted",
+ "color_strip.delete.confirm": "Are you sure you want to delete this color strip source?",
+ "color_strip.delete.referenced": "Cannot delete: this source is in use by a target",
+ "color_strip.error.name_required": "Please enter a name",
+ "color_strip.type": "Type:",
+ "color_strip.type.hint": "Picture Source derives LED colors from a screen capture. Static Color fills all LEDs with a single constant color. Gradient distributes a color gradient across all LEDs. Color Cycle smoothly cycles through a user-defined list of colors. Composite stacks multiple sources as blended layers. Audio Reactive drives LEDs from real-time audio input. API Input receives raw LED colors from external clients via REST or WebSocket.",
+ "color_strip.type.picture": "Picture Source",
+ "color_strip.type.picture.desc": "Colors from screen capture",
+ "color_strip.type.picture_advanced": "Multi-Monitor",
+ "color_strip.type.picture_advanced.desc": "Line-based calibration across monitors",
+ "color_strip.type.static": "Static Color",
+ "color_strip.type.static.desc": "Single solid color fill",
+ "color_strip.type.gradient": "Gradient",
+ "color_strip.type.gradient.desc": "Smooth color transition across LEDs",
+ "color_strip.type.color_cycle": "Color Cycle",
+ "color_strip.type.color_cycle.desc": "Cycle through a list of colors",
+ "color_strip.static_color": "Color:",
+ "color_strip.static_color.hint": "The solid color that will be sent to all LEDs on the strip.",
+ "color_strip.gradient.preview": "Gradient:",
+ "color_strip.gradient.preview.hint": "Visual preview. Click the marker track below to add a stop. Drag markers to reposition.",
+ "color_strip.gradient.stops": "Color Stops:",
+ "color_strip.gradient.stops.hint": "Each stop defines a color at a relative position (0.0 = start, 1.0 = end). The ↔ button adds a right-side color to create a hard edge at that stop.",
+ "color_strip.gradient.stops_count": "stops",
+ "color_strip.gradient.add_stop": "+ Add Stop",
+ "color_strip.gradient.position": "Position (0.0–1.0)",
+ "color_strip.gradient.bidir.hint": "Add a second color on the right side of this stop to create a hard edge in the gradient.",
+ "color_strip.gradient.min_stops": "Gradient must have at least 2 stops",
+ "color_strip.gradient.preset": "Preset:",
+ "color_strip.gradient.preset.hint": "Load a predefined gradient palette. Selecting a preset replaces the current stops.",
+ "color_strip.gradient.preset.custom": "— Custom —",
+ "color_strip.gradient.preset.rainbow": "Rainbow",
+ "color_strip.gradient.preset.sunset": "Sunset",
+ "color_strip.gradient.preset.ocean": "Ocean",
+ "color_strip.gradient.preset.forest": "Forest",
+ "color_strip.gradient.preset.fire": "Fire",
+ "color_strip.gradient.preset.lava": "Lava",
+ "color_strip.gradient.preset.aurora": "Aurora",
+ "color_strip.gradient.preset.ice": "Ice",
+ "color_strip.gradient.preset.warm": "Warm",
+ "color_strip.gradient.preset.cool": "Cool",
+ "color_strip.gradient.preset.neon": "Neon",
+ "color_strip.gradient.preset.pastel": "Pastel",
+ "color_strip.gradient.preset.save_button": "Save as preset…",
+ "color_strip.gradient.preset.save_prompt": "Enter a name for this preset:",
+ "color_strip.gradient.preset.saved": "Preset saved",
+ "color_strip.gradient.preset.deleted": "Preset deleted",
+ "color_strip.gradient.preset.apply": "Apply",
+ "color_strip.animation": "Animation",
+ "color_strip.animation.type": "Effect:",
+ "color_strip.animation.type.hint": "Animation effect to apply.",
+ "color_strip.animation.type.none": "None (no animation effect)",
+ "color_strip.animation.type.none.desc": "Static colors with no animation",
+ "color_strip.animation.type.breathing": "Breathing",
+ "color_strip.animation.type.breathing.desc": "Smooth brightness fade in and out",
+ "color_strip.animation.type.color_cycle": "Color Cycle",
+ "color_strip.animation.type.gradient_shift": "Gradient Shift",
+ "color_strip.animation.type.gradient_shift.desc": "Slides the gradient along the strip",
+ "color_strip.animation.type.wave": "Wave",
+ "color_strip.animation.type.wave.desc": "Sinusoidal brightness wave moving along the strip",
+ "color_strip.animation.type.strobe": "Strobe",
+ "color_strip.animation.type.strobe.desc": "Rapid on/off flashing",
+ "color_strip.animation.type.sparkle": "Sparkle",
+ "color_strip.animation.type.sparkle.desc": "Random LEDs flash briefly",
+ "color_strip.animation.type.pulse": "Pulse",
+ "color_strip.animation.type.pulse.desc": "Sharp brightness pulse with quick fade",
+ "color_strip.animation.type.candle": "Candle",
+ "color_strip.animation.type.candle.desc": "Warm flickering candle-like glow",
+ "color_strip.animation.type.rainbow_fade": "Rainbow Fade",
+ "color_strip.animation.type.rainbow_fade.desc": "Cycles through the entire hue spectrum",
+ "color_strip.animation.speed": "Speed:",
+ "color_strip.animation.speed.hint": "Animation speed multiplier. 1.0 ≈ one cycle per second for Breathing; higher values cycle faster.",
+ "color_strip.color_cycle.colors": "Colors:",
+ "color_strip.color_cycle.colors.hint": "List of colors to cycle through smoothly. At least 2 required. Default is a full rainbow spectrum.",
+ "color_strip.color_cycle.add_color": "+ Add Color",
+ "color_strip.color_cycle.speed": "Speed:",
+ "color_strip.color_cycle.speed.hint": "Cycle speed multiplier. 1.0 ≈ one full cycle every 20 seconds; higher values cycle faster.",
+ "color_strip.color_cycle.min_colors": "Color cycle must have at least 2 colors",
+ "color_strip.type.effect": "Effect",
+ "color_strip.type.effect.desc": "Procedural effects like fire, plasma, aurora",
+ "color_strip.type.effect.hint": "Procedural LED effects (fire, meteor, plasma, noise, aurora) generated in real time.",
+ "color_strip.type.composite": "Composite",
+ "color_strip.type.composite.desc": "Stack and blend multiple sources",
+ "color_strip.type.composite.hint": "Stack multiple color strip sources as layers with blend modes and opacity.",
+ "color_strip.type.mapped": "Mapped",
+ "color_strip.type.mapped.desc": "Assign sources to LED zones",
+ "color_strip.type.mapped.hint": "Assign different color strip sources to different LED ranges (zones). Unlike composite which blends layers, mapped places sources side-by-side.",
+ "color_strip.type.audio": "Audio Reactive",
+ "color_strip.type.audio.desc": "LEDs driven by audio input",
+ "color_strip.type.audio.hint": "LED colors driven by real-time audio input — system audio or microphone.",
+ "color_strip.type.api_input": "API Input",
+ "color_strip.type.api_input.desc": "Receive colors from external apps",
+ "color_strip.type.api_input.hint": "Receives raw LED color arrays from external clients via REST POST or WebSocket. Use this to integrate with custom software, home automation, or any system that can send HTTP requests.",
+ "color_strip.api_input.fallback_color": "Fallback Color:",
+ "color_strip.api_input.fallback_color.hint": "Color to display when no data has been received within the timeout period. LEDs will show this color on startup and after the connection is lost.",
+ "color_strip.api_input.timeout": "Timeout (seconds):",
+ "color_strip.api_input.timeout.hint": "How long to wait for new color data before reverting to the fallback color. Set to 0 to never time out.",
+ "color_strip.api_input.endpoints": "Push Endpoints:",
+ "color_strip.api_input.endpoints.hint": "Use these URLs to push LED color data from your external application. REST accepts JSON, WebSocket accepts both JSON and raw binary frames.",
+ "color_strip.api_input.save_first": "Save the source first to see the push endpoint URLs.",
+ "color_strip.type.notification": "Notification",
+ "color_strip.type.notification.desc": "One-shot effect on webhook trigger",
+ "color_strip.type.notification.hint": "Fires a one-shot visual effect (flash, pulse, sweep) when triggered via a webhook. Designed for use as a composite layer over a persistent base source.",
+ "color_strip.notification.effect": "Effect:",
+ "color_strip.notification.effect.hint": "Visual effect when a notification fires. Flash fades linearly, Pulse uses a smooth bell curve, Sweep fills LEDs left-to-right then fades.",
+ "color_strip.notification.effect.flash": "Flash",
+ "color_strip.notification.effect.flash.desc": "Instant on, linear fade-out",
+ "color_strip.notification.effect.pulse": "Pulse",
+ "color_strip.notification.effect.pulse.desc": "Smooth bell-curve glow",
+ "color_strip.notification.effect.sweep": "Sweep",
+ "color_strip.notification.effect.sweep.desc": "Fills left-to-right then fades",
+ "color_strip.notification.duration": "Duration (ms):",
+ "color_strip.notification.duration.hint": "How long the notification effect plays, in milliseconds.",
+ "color_strip.notification.default_color": "Default Color:",
+ "color_strip.notification.default_color.hint": "Color used when the notification has no app-specific color mapping.",
+ "color_strip.notification.filter_mode": "App Filter:",
+ "color_strip.notification.filter_mode.hint": "Filter notifications by app name. Off = accept all, Whitelist = only listed apps, Blacklist = all except listed apps.",
+ "color_strip.notification.filter_mode.off": "Off",
+ "color_strip.notification.filter_mode.whitelist": "Whitelist",
+ "color_strip.notification.filter_mode.blacklist": "Blacklist",
+ "color_strip.notification.filter_mode.off.desc": "Accept all notifications",
+ "color_strip.notification.filter_mode.whitelist.desc": "Only listed apps",
+ "color_strip.notification.filter_mode.blacklist.desc": "All except listed apps",
+ "color_strip.notification.filter_list": "App List:",
+ "color_strip.notification.filter_list.hint": "One app name per line. Use Browse to pick from running processes.",
+ "color_strip.notification.filter_list.placeholder": "Discord\nSlack\nTelegram",
+ "color_strip.notification.app_colors": "App Colors",
+ "color_strip.notification.app_colors.label": "Color Mappings:",
+ "color_strip.notification.app_colors.hint": "Per-app color overrides. Each row maps an app name to a specific notification color.",
+ "color_strip.notification.app_colors.add": "+ Add Mapping",
+ "color_strip.notification.endpoint": "Webhook Endpoint:",
+ "color_strip.notification.endpoint.hint": "Use this URL to trigger notifications from external systems. POST with optional JSON body: {\"app\": \"AppName\", \"color\": \"#FF0000\"}.",
+ "color_strip.notification.save_first": "Save the source first to see the webhook endpoint URL.",
+ "color_strip.notification.app_count": "apps",
+ "color_strip.notification.test": "Test notification",
+ "color_strip.notification.test.ok": "Notification sent",
+ "color_strip.notification.test.no_streams": "No running streams for this source",
+ "color_strip.notification.test.error": "Failed to send notification",
+ "color_strip.notification.history.title": "Notification History",
+ "color_strip.notification.history.hint": "Recent OS notifications captured by the listener (newest first). Up to 50 entries.",
+ "color_strip.notification.history.empty": "No notifications captured yet",
+ "color_strip.notification.history.unavailable": "OS notification listener is not available on this platform",
+ "color_strip.notification.history.error": "Failed to load notification history",
+ "color_strip.notification.history.refresh": "Refresh",
+ "color_strip.notification.history.unknown_app": "Unknown app",
+ "color_strip.notification.history.fired": "Streams triggered",
+ "color_strip.notification.history.filtered": "Streams filtered",
+ "color_strip.test.title": "Test Preview",
+ "color_strip.test.connecting": "Connecting...",
+ "color_strip.test.error": "Failed to connect to preview stream",
+ "color_strip.test.led_count": "LEDs:",
+ "color_strip.test.fps": "FPS:",
+ "color_strip.test.receive_fps": "Receive FPS",
+ "color_strip.test.apply": "Apply",
+ "color_strip.test.composite": "Composite",
+ "color_strip.preview.title": "Live Preview",
+ "color_strip.preview.not_connected": "Not connected",
+ "color_strip.preview.connecting": "Connecting...",
+ "color_strip.preview.connected": "Connected",
+ "color_strip.preview.unsupported": "Preview not available for this source type",
+ "color_strip.type.daylight": "Daylight Cycle",
+ "color_strip.type.daylight.desc": "Simulates natural daylight over 24 hours",
+ "color_strip.type.daylight.hint": "Simulates the sun's color temperature throughout a 24-hour day/night cycle — from warm sunrise to cool daylight to warm sunset and dim night.",
+ "color_strip.daylight.speed": "Speed:",
+ "color_strip.daylight.speed.hint": "Cycle speed multiplier. 1.0 = full day/night cycle in ~4 minutes. Higher values cycle faster.",
+ "color_strip.daylight.use_real_time": "Use Real Time:",
+ "color_strip.daylight.use_real_time.hint": "When enabled, LED color matches the actual time of day on this computer. Speed setting is ignored.",
+ "color_strip.daylight.real_time": "Real Time",
+ "color_strip.daylight.latitude": "Latitude:",
+ "color_strip.daylight.latitude.hint": "Your geographic latitude (-90 to 90). Affects sunrise/sunset timing in real-time mode.",
+ "color_strip.type.candlelight": "Candlelight",
+ "color_strip.type.candlelight.desc": "Realistic flickering candle simulation",
+ "color_strip.type.candlelight.hint": "Simulates realistic candle flickering across all LEDs with warm tones and organic flicker patterns.",
+ "color_strip.candlelight.color": "Base Color:",
+ "color_strip.candlelight.color.hint": "The warm base color of the candle flame. Default is a natural warm amber.",
+ "color_strip.candlelight.intensity": "Flicker Intensity:",
+ "color_strip.candlelight.intensity.hint": "How much the candles flicker. Low values produce a gentle glow, high values simulate a windy candle.",
+ "color_strip.candlelight.num_candles_label": "Number of Candles:",
+ "color_strip.candlelight.num_candles": "candles",
+ "color_strip.candlelight.num_candles.hint": "How many independent candle sources along the strip. Each flickers with its own pattern.",
+ "color_strip.candlelight.speed": "Flicker Speed:",
+ "color_strip.candlelight.speed.hint": "Speed of the flicker animation. Higher values produce faster, more restless flames.",
+ "color_strip.type.processed": "Processed",
+ "color_strip.type.processed.desc": "Apply a processing template to another source",
+ "color_strip.type.processed.hint": "Wraps an existing color strip source and pipes its output through a filter chain.",
+ "color_strip.processed.input": "Source:",
+ "color_strip.processed.input.hint": "The color strip source whose output will be processed",
+ "color_strip.processed.template": "Processing Template:",
+ "color_strip.processed.template.hint": "Filter chain to apply to the input source output",
+ "color_strip.processed.error.no_input": "Please select an input source",
+ "color_strip.composite.layers": "Layers:",
+ "color_strip.composite.layers.hint": "Stack multiple color strip sources. First layer is the bottom, last is the top. Each layer can have its own blend mode and opacity.",
+ "color_strip.composite.add_layer": "+ Add Layer",
+ "color_strip.composite.source": "Source",
+ "color_strip.composite.blend_mode": "Blend",
+ "color_strip.composite.blend_mode.normal": "Normal",
+ "color_strip.composite.blend_mode.normal.desc": "Standard alpha blending",
+ "color_strip.composite.blend_mode.add": "Add",
+ "color_strip.composite.blend_mode.add.desc": "Brightens by adding colors",
+ "color_strip.composite.blend_mode.multiply": "Multiply",
+ "color_strip.composite.blend_mode.multiply.desc": "Darkens by multiplying colors",
+ "color_strip.composite.blend_mode.screen": "Screen",
+ "color_strip.composite.blend_mode.screen.desc": "Brightens, inverse of multiply",
+ "color_strip.composite.blend_mode.override": "Override",
+ "color_strip.composite.blend_mode.override.desc": "Black = transparent, bright = opaque",
+ "color_strip.composite.opacity": "Opacity",
+ "color_strip.composite.brightness": "Brightness",
+ "color_strip.composite.brightness.none": "None (full brightness)",
+ "color_strip.composite.processing": "Processing",
+ "color_strip.composite.enabled": "Enabled",
+ "color_strip.composite.error.min_layers": "At least 1 layer is required",
+ "color_strip.composite.error.no_source": "Each layer must have a source selected",
+ "color_strip.composite.layers_count": "layers",
+ "color_strip.mapped.zones": "Zones:",
+ "color_strip.mapped.zones.hint": "Each zone maps a color strip source to a specific LED range. Zones are placed side-by-side — gaps between zones stay black.",
+ "color_strip.mapped.add_zone": "+ Add Zone",
+ "color_strip.mapped.zone_source": "Source",
+ "color_strip.mapped.zone_start": "Start LED",
+ "color_strip.mapped.zone_end": "End LED",
+ "color_strip.mapped.zone_reverse": "Reverse",
+ "color_strip.mapped.zones_count": "zones",
+ "color_strip.mapped.select_source": "Search sources...",
+ "color_strip.mapped.error.no_source": "Each zone must have a source selected",
+ "color_strip.audio.visualization": "Visualization:",
+ "color_strip.audio.visualization.hint": "How audio data is rendered to LEDs.",
+ "color_strip.audio.viz.spectrum": "Spectrum Analyzer",
+ "color_strip.audio.viz.spectrum.desc": "Frequency bars across the strip",
+ "color_strip.audio.viz.beat_pulse": "Beat Pulse",
+ "color_strip.audio.viz.beat_pulse.desc": "All LEDs pulse on the beat",
+ "color_strip.audio.viz.vu_meter": "VU Meter",
+ "color_strip.audio.viz.vu_meter.desc": "Volume level fills the strip",
+ "color_strip.audio.source": "Audio Source:",
+ "color_strip.audio.source.hint": "Audio source for this visualization. Can be a multichannel (device) or mono (single channel) source. Create and manage audio sources in the Sources tab.",
+ "color_strip.audio.sensitivity": "Sensitivity:",
+ "color_strip.audio.sensitivity.hint": "Gain multiplier for audio levels. Higher values make LEDs react to quieter sounds.",
+ "color_strip.audio.smoothing": "Smoothing:",
+ "color_strip.audio.smoothing.hint": "Temporal smoothing between frames. Higher values produce smoother but slower-reacting visuals.",
+ "color_strip.audio.palette": "Palette:",
+ "color_strip.audio.palette.hint": "Color palette used for spectrum bars or beat pulse coloring.",
+ "color_strip.audio.color": "Base Color:",
+ "color_strip.audio.color.hint": "Low-level color for VU meter bar.",
+ "color_strip.audio.color_peak": "Peak Color:",
+ "color_strip.audio.color_peak.hint": "High-level color at the top of the VU meter bar.",
+ "color_strip.audio.mirror": "Mirror:",
+ "color_strip.audio.mirror.hint": "Mirror spectrum from center outward: bass in the middle, treble at the edges.",
+ "color_strip.effect.type": "Effect Type:",
+ "color_strip.effect.type.hint": "Choose the procedural algorithm.",
+ "color_strip.effect.fire": "Fire",
+ "color_strip.effect.fire.desc": "Cellular automaton simulating rising flames with heat diffusion",
+ "color_strip.effect.meteor": "Meteor",
+ "color_strip.effect.meteor.desc": "Bright head travels along the strip with an exponential-decay tail",
+ "color_strip.effect.plasma": "Plasma",
+ "color_strip.effect.plasma.desc": "Overlapping sine waves mapped to a palette — classic demo-scene effect",
+ "color_strip.effect.noise": "Noise",
+ "color_strip.effect.noise.desc": "Scrolling fractal value noise mapped to a palette",
+ "color_strip.effect.aurora": "Aurora",
+ "color_strip.effect.aurora.desc": "Layered noise bands that drift and blend — northern lights style",
+ "color_strip.effect.speed": "Speed:",
+ "color_strip.effect.speed.hint": "Speed multiplier for the effect animation (0.1 = very slow, 10.0 = very fast).",
+ "color_strip.effect.palette": "Palette:",
+ "color_strip.effect.palette.hint": "Color palette used to map effect values to RGB colors.",
+ "color_strip.effect.color": "Meteor Color:",
+ "color_strip.effect.color.hint": "Head color for the meteor effect.",
+ "color_strip.effect.intensity": "Intensity:",
+ "color_strip.effect.intensity.hint": "Effect intensity — controls spark rate (fire), tail decay (meteor), or brightness range (aurora).",
+ "color_strip.effect.scale": "Scale:",
+ "color_strip.effect.scale.hint": "Spatial scale — wave frequency (plasma), zoom level (noise), or band width (aurora).",
+ "color_strip.effect.mirror": "Mirror:",
+ "color_strip.effect.mirror.hint": "Bounce mode — the meteor reverses direction at strip ends instead of wrapping.",
+ "color_strip.palette.fire": "Fire",
+ "color_strip.palette.ocean": "Ocean",
+ "color_strip.palette.lava": "Lava",
+ "color_strip.palette.forest": "Forest",
+ "color_strip.palette.rainbow": "Rainbow",
+ "color_strip.palette.aurora": "Aurora",
+ "color_strip.palette.sunset": "Sunset",
+ "color_strip.palette.ice": "Ice",
+ "audio_source.title": "Audio Sources",
+ "audio_source.group.multichannel": "Multichannel",
+ "audio_source.group.mono": "Mono",
+ "audio_source.add": "Add Audio Source",
+ "audio_source.add.multichannel": "Add Multichannel Source",
+ "audio_source.add.mono": "Add Mono Source",
+ "audio_source.edit": "Edit Audio Source",
+ "audio_source.edit.multichannel": "Edit Multichannel Source",
+ "audio_source.edit.mono": "Edit Mono Source",
+ "audio_source.name": "Name:",
+ "audio_source.name.placeholder": "System Audio",
+ "audio_source.name.hint": "A descriptive name for this audio source",
+ "audio_source.type": "Type:",
+ "audio_source.type.hint": "Multichannel captures all channels from a physical audio device. Mono extracts a single channel from a multichannel source.",
+ "audio_source.type.multichannel": "Multichannel",
+ "audio_source.type.mono": "Mono",
+ "audio_source.device": "Audio Device:",
+ "audio_source.device.hint": "Audio input source. Loopback devices capture system audio output; input devices capture microphone or line-in.",
+ "audio_source.refresh_devices": "Refresh devices",
+ "audio_source.parent": "Parent Source:",
+ "audio_source.parent.hint": "Multichannel source to extract a channel from",
+ "audio_source.channel": "Channel:",
+ "audio_source.channel.hint": "Which audio channel to extract from the multichannel source",
+ "audio_source.channel.mono": "Mono (L+R mix)",
+ "audio_source.channel.left": "Left",
+ "audio_source.channel.right": "Right",
+ "audio_source.description": "Description (optional):",
+ "audio_source.description.placeholder": "Describe this audio source...",
+ "audio_source.description.hint": "Optional notes about this audio source",
+ "audio_source.created": "Audio source created",
+ "audio_source.updated": "Audio source updated",
+ "audio_source.deleted": "Audio source deleted",
+ "audio_source.delete.confirm": "Are you sure you want to delete this audio source?",
+ "audio_source.error.name_required": "Please enter a name",
+ "audio_source.audio_template": "Audio Template:",
+ "audio_source.audio_template.hint": "Audio capture template that defines which engine and settings to use for this device",
+ "audio_source.test": "Test",
+ "audio_source.test.title": "Test Audio Source",
+ "audio_source.test.rms": "RMS",
+ "audio_source.test.peak": "Peak",
+ "audio_source.test.beat": "Beat",
+ "audio_source.test.connecting": "Connecting...",
+ "audio_source.test.error": "Audio test failed",
+ "audio_template.test": "Test",
+ "audio_template.test.title": "Test Audio Template",
+ "audio_template.test.device": "Audio Device:",
+ "audio_template.test.device.hint": "Select which audio device to capture from during the test",
+ "audio_template.test.run": "Run",
+ "audio_template.title": "Audio Templates",
+ "audio_template.add": "Add Audio Template",
+ "audio_template.edit": "Edit Audio Template",
+ "audio_template.name": "Template Name:",
+ "audio_template.name.placeholder": "My Audio Template",
+ "audio_template.description.label": "Description (optional):",
+ "audio_template.description.placeholder": "Describe this template...",
+ "audio_template.engine": "Audio Engine:",
+ "audio_template.engine.hint": "Select the audio capture backend to use. WASAPI is Windows-only with loopback support. Sounddevice is cross-platform.",
+ "audio_template.engine.unavailable": "Unavailable",
+ "audio_template.engine.unavailable.hint": "This engine is not available on your system",
+ "audio_template.config": "Configuration",
+ "audio_template.config.show": "Show configuration",
+ "audio_template.created": "Audio template created",
+ "audio_template.updated": "Audio template updated",
+ "audio_template.deleted": "Audio template deleted",
+ "audio_template.delete.confirm": "Are you sure you want to delete this audio template?",
+ "audio_template.error.load": "Failed to load audio templates",
+ "audio_template.error.engines": "Failed to load audio engines",
+ "audio_template.error.required": "Please fill in all required fields",
+ "audio_template.error.delete": "Failed to delete audio template",
+ "streams.group.value": "Value Sources",
+ "streams.group.sync": "Sync Clocks",
+ "tree.group.picture": "Picture Source",
+ "tree.group.capture": "Screen Capture",
+ "tree.group.static": "Static",
+ "tree.group.processing": "Processed",
+ "tree.group.strip": "Color Strip",
+ "tree.group.audio": "Audio",
+ "tree.group.utility": "Utility",
+ "tree.leaf.sources": "Sources",
+ "tree.leaf.engine_templates": "Engine Templates",
+ "tree.leaf.images": "Images",
+ "tree.leaf.video": "Video",
+ "tree.leaf.filter_templates": "Filter Templates",
+ "tree.leaf.processing_templates": "Processing Templates",
+ "tree.leaf.templates": "Templates",
+ "value_source.group.title": "Value Sources",
+ "value_source.select_type": "Select Value Source Type",
+ "value_source.add": "Add Value Source",
+ "value_source.edit": "Edit Value Source",
+ "value_source.name": "Name:",
+ "value_source.name.placeholder": "Brightness Pulse",
+ "value_source.name.hint": "A descriptive name for this value source",
+ "value_source.type": "Type:",
+ "value_source.type.hint": "Static outputs a constant value. Animated cycles through a waveform. Audio reacts to sound input. Adaptive types adjust brightness automatically based on time of day or scene content.",
+ "value_source.type.static": "Static",
+ "value_source.type.static.desc": "Constant output value",
+ "value_source.type.animated": "Animated",
+ "value_source.type.animated.desc": "Cycles through a waveform",
+ "value_source.type.audio": "Audio",
+ "value_source.type.audio.desc": "Reacts to sound input",
+ "value_source.type.adaptive_time": "Adaptive (Time)",
+ "value_source.type.adaptive_time.desc": "Adjusts by time of day",
+ "value_source.type.adaptive_scene": "Adaptive (Scene)",
+ "value_source.type.adaptive_scene.desc": "Adjusts by scene content",
+ "value_source.type.daylight": "Daylight Cycle",
+ "value_source.type.daylight.desc": "Brightness follows day/night cycle",
+ "value_source.daylight.speed": "Speed:",
+ "value_source.daylight.speed.hint": "Cycle speed multiplier. 1.0 = full day/night cycle in ~4 minutes. Higher values cycle faster.",
+ "value_source.daylight.use_real_time": "Use Real Time:",
+ "value_source.daylight.use_real_time.hint": "When enabled, brightness follows the actual time of day. Speed is ignored.",
+ "value_source.daylight.enable_real_time": "Follow wall clock",
+ "value_source.daylight.latitude": "Latitude:",
+ "value_source.daylight.latitude.hint": "Your geographic latitude (-90 to 90). Affects sunrise/sunset timing in real-time mode.",
+ "value_source.daylight.real_time": "Real-time",
+ "value_source.daylight.speed_label": "Speed",
+ "value_source.value": "Value:",
+ "value_source.value.hint": "Constant output value (0.0 = off, 1.0 = full brightness)",
+ "value_source.waveform": "Waveform:",
+ "value_source.waveform.hint": "Shape of the brightness animation cycle",
+ "value_source.waveform.sine": "Sine",
+ "value_source.waveform.triangle": "Triangle",
+ "value_source.waveform.square": "Square",
+ "value_source.waveform.sawtooth": "Sawtooth",
+ "value_source.speed": "Speed (cpm):",
+ "value_source.speed.hint": "Cycles per minute — how fast the waveform repeats (1 = very slow, 120 = very fast)",
+ "value_source.min_value": "Min Value:",
+ "value_source.min_value.hint": "Minimum output of the waveform cycle",
+ "value_source.max_value": "Max Value:",
+ "value_source.max_value.hint": "Maximum output of the waveform cycle",
+ "value_source.audio_source": "Audio Source:",
+ "value_source.audio_source.hint": "Audio source to read audio levels from (multichannel or mono)",
+ "value_source.mode": "Mode:",
+ "value_source.mode.hint": "RMS measures average volume. Peak tracks loudest moments. Beat triggers on rhythm.",
+ "value_source.mode.rms": "RMS (Volume)",
+ "value_source.mode.peak": "Peak",
+ "value_source.mode.beat": "Beat",
+ "value_source.mode.rms.desc": "Average volume level",
+ "value_source.mode.peak.desc": "Loudest moment tracking",
+ "value_source.mode.beat.desc": "Rhythm pulse detection",
+ "value_source.auto_gain": "Auto Gain:",
+ "value_source.auto_gain.hint": "Automatically normalize audio levels so output uses the full range, regardless of input volume",
+ "value_source.auto_gain.enable": "Enable auto-gain",
+ "value_source.sensitivity": "Sensitivity:",
+ "value_source.sensitivity.hint": "Gain multiplier for the audio signal (higher = more reactive)",
+ "value_source.scene_sensitivity.hint": "Gain multiplier for the luminance signal (higher = more reactive to brightness changes)",
+ "value_source.smoothing": "Smoothing:",
+ "value_source.smoothing.hint": "Temporal smoothing (0 = instant response, 1 = very smooth/slow)",
+ "value_source.audio_min_value": "Min Value:",
+ "value_source.audio_min_value.hint": "Output when audio is silent (e.g. 0.3 = 30% brightness floor)",
+ "value_source.audio_max_value": "Max Value:",
+ "value_source.audio_max_value.hint": "Output at maximum audio level",
+ "value_source.schedule": "Schedule:",
+ "value_source.schedule.hint": "Define at least 2 time points. Brightness interpolates linearly between them, wrapping at midnight.",
+ "value_source.schedule.add": "+ Add Point",
+ "value_source.schedule.points": "points",
+ "value_source.picture_source": "Picture Source:",
+ "value_source.picture_source.hint": "The picture source whose frames will be analyzed for average brightness.",
+ "value_source.scene_behavior": "Behavior:",
+ "value_source.scene_behavior.hint": "Complement: dark scene = high brightness (ideal for ambient backlight). Match: bright scene = high brightness.",
+ "value_source.scene_behavior.complement": "Complement (dark → bright)",
+ "value_source.scene_behavior.match": "Match (bright → bright)",
+ "value_source.adaptive_min_value": "Min Value:",
+ "value_source.adaptive_min_value.hint": "Minimum output brightness",
+ "value_source.adaptive_max_value": "Max Value:",
+ "value_source.adaptive_max_value.hint": "Maximum output brightness",
+ "value_source.error.schedule_min": "Schedule requires at least 2 time points",
+ "value_source.description": "Description (optional):",
+ "value_source.description.placeholder": "Describe this value source...",
+ "value_source.description.hint": "Optional notes about this value source",
+ "value_source.created": "Value source created",
+ "value_source.updated": "Value source updated",
+ "value_source.deleted": "Value source deleted",
+ "value_source.delete.confirm": "Are you sure you want to delete this value source?",
+ "value_source.error.name_required": "Please enter a name",
+ "value_source.test": "Test",
+ "value_source.test.title": "Test Value Source",
+ "value_source.test.connecting": "Connecting...",
+ "value_source.test.error": "Failed to connect",
+ "value_source.test.current": "Current",
+ "value_source.test.min": "Min",
+ "value_source.test.max": "Max",
+ "test.frames": "Frames",
+ "test.fps": "FPS",
+ "test.avg_capture": "Avg",
+ "targets.brightness_vs": "Brightness Source:",
+ "targets.brightness_vs.hint": "Optional value source that dynamically controls brightness each frame (overrides device brightness)",
+ "targets.brightness_vs.none": "None (device brightness)",
+ "targets.min_brightness_threshold": "Min Brightness Threshold:",
+ "targets.min_brightness_threshold.hint": "Effective output brightness (pixel brightness × device/source brightness) below this value turns LEDs off completely (0 = disabled)",
+ "targets.adaptive_fps": "Adaptive FPS:",
+ "targets.adaptive_fps.hint": "Automatically reduce send rate when the device becomes unresponsive, and gradually recover when it stabilizes. Recommended for WiFi devices with weak signal.",
+ "targets.protocol": "Protocol:",
+ "targets.protocol.hint": "DDP sends pixels via fast UDP (recommended for most setups). HTTP uses the JSON API — slower but reliable, limited to ~500 LEDs.",
+ "targets.protocol.ddp": "DDP (UDP)",
+ "targets.protocol.ddp.desc": "Fast raw UDP packets — recommended",
+ "targets.protocol.http": "HTTP",
+ "targets.protocol.http.desc": "JSON API — slower, ≤500 LEDs",
+ "targets.protocol.serial": "Serial",
+ "search.open": "Search (Ctrl+K)",
+ "search.placeholder": "Search entities... (Ctrl+K)",
+ "search.loading": "Loading...",
+ "search.no_results": "No results found",
+ "search.group.devices": "Devices",
+ "search.group.targets": "LED Targets",
+ "search.group.kc_targets": "Key Colors Targets",
+ "search.group.css": "Color Strip Sources",
+ "search.group.automations": "Automations",
+ "search.group.streams": "Picture Streams",
+ "search.group.capture_templates": "Capture Templates",
+ "search.group.pp_templates": "Post-Processing Templates",
+ "search.group.pattern_templates": "Pattern Templates",
+ "search.group.audio": "Audio Sources",
+ "search.group.value": "Value Sources",
+ "search.group.scenes": "Scene Presets",
+ "search.group.cspt": "Strip Processing Templates",
+ "search.group.sync_clocks": "Sync Clocks",
+ "search.group.actions": "Actions",
+ "search.action.start": "Start",
+ "search.action.stop": "Stop",
+ "search.action.activate": "Activate",
+ "search.action.enable": "Enable",
+ "search.action.disable": "Disable",
+ "settings.backup.label": "Backup Configuration",
+ "settings.backup.hint": "Download all configuration (devices, targets, streams, templates, automations) as a single JSON file.",
+ "settings.backup.button": "Download Backup",
+ "settings.backup.success": "Backup downloaded successfully",
+ "settings.backup.error": "Backup download failed",
+ "settings.restore.label": "Restore Configuration",
+ "settings.restore.hint": "Upload a previously downloaded backup file to replace all configuration. The server will restart automatically.",
+ "settings.restore.button": "Restore from Backup",
+ "settings.restore.confirm": "This will replace ALL configuration and restart the server. Are you sure?",
+ "settings.restore.success": "Configuration restored",
+ "settings.restore.error": "Restore failed",
+ "settings.restore.restarting": "Server is restarting...",
+ "settings.restore.restart_timeout": "Server did not respond. Please refresh the page manually.",
+ "settings.restart_server": "Restart Server",
+ "settings.restart_confirm": "Restart the server? Active targets will be stopped.",
+ "settings.restarting": "Restarting server...",
+ "settings.button.close": "Close",
+ "settings.log_level.label": "Log Level",
+ "settings.log_level.hint": "Change the server log verbosity at runtime. DEBUG shows the most detail; CRITICAL shows only fatal errors.",
+ "settings.log_level.save": "Apply",
+ "settings.log_level.saved": "Log level changed",
+ "settings.log_level.save_error": "Failed to change log level",
+ "settings.log_level.desc.debug": "Verbose developer output",
+ "settings.log_level.desc.info": "Normal operation messages",
+ "settings.log_level.desc.warning": "Potential problems",
+ "settings.log_level.desc.error": "Failures only",
+ "settings.log_level.desc.critical": "Fatal errors only",
+ "settings.auto_backup.label": "Auto-Backup",
+ "settings.auto_backup.hint": "Automatically create periodic backups of all configuration. Old backups are pruned when the maximum count is reached.",
+ "settings.auto_backup.enable": "Enable auto-backup",
+ "settings.auto_backup.interval_label": "Interval",
+ "settings.auto_backup.max_label": "Max backups",
+ "settings.auto_backup.save": "Save Settings",
+ "settings.auto_backup.saved": "Auto-backup settings saved",
+ "settings.auto_backup.save_error": "Failed to save auto-backup settings",
+ "settings.auto_backup.last_backup": "Last backup",
+ "settings.auto_backup.never": "Never",
+ "settings.saved_backups.label": "Saved Backups",
+ "settings.saved_backups.hint": "Auto-backup files stored on the server. Download to save locally, or delete to free space.",
+ "settings.saved_backups.empty": "No saved backups",
+ "settings.saved_backups.restore": "Restore",
+ "settings.saved_backups.download": "Download",
+ "settings.saved_backups.delete": "Delete",
+ "settings.saved_backups.delete_confirm": "Delete this backup file?",
+ "settings.saved_backups.delete_error": "Failed to delete backup",
+ "settings.saved_backups.type.auto": "auto",
+ "settings.saved_backups.type.manual": "manual",
+ "settings.mqtt.label": "MQTT",
+ "settings.mqtt.hint": "Configure MQTT broker connection for automation conditions and triggers.",
+ "settings.mqtt.enabled": "Enable MQTT",
+ "settings.mqtt.host_label": "Broker Host",
+ "settings.mqtt.port_label": "Port",
+ "settings.mqtt.username_label": "Username",
+ "settings.mqtt.password_label": "Password",
+ "settings.mqtt.password_set_hint": "Password is set — leave blank to keep",
+ "settings.mqtt.client_id_label": "Client ID",
+ "settings.mqtt.base_topic_label": "Base Topic",
+ "settings.mqtt.save": "Save MQTT Settings",
+ "settings.mqtt.saved": "MQTT settings saved",
+ "settings.mqtt.save_error": "Failed to save MQTT settings",
+ "settings.mqtt.error_host_required": "Broker host is required",
+ "settings.logs.label": "Server Logs",
+ "settings.logs.hint": "Stream live server log output. Use the filter to show only relevant log levels.",
+ "settings.logs.connect": "Connect",
+ "settings.logs.disconnect": "Disconnect",
+ "settings.logs.clear": "Clear",
+ "settings.logs.error": "Log viewer connection failed",
+ "settings.logs.filter.all": "All levels",
+ "settings.logs.filter.info": "Info+",
+ "settings.logs.filter.warning": "Warning+",
+ "settings.logs.filter.error": "Error only",
+ "settings.logs.filter.all_desc": "Show all log messages",
+ "settings.logs.filter.info_desc": "Info, warning, and errors",
+ "settings.logs.filter.warning_desc": "Warnings and errors only",
+ "settings.logs.filter.error_desc": "Errors only",
+ "device.error.power_off_failed": "Failed to turn off device",
+ "device.error.remove_failed": "Failed to remove device",
+ "device.error.settings_load_failed": "Failed to load device settings",
+ "device.error.brightness": "Failed to update brightness",
+ "device.error.required": "Please fill in all fields correctly",
+ "device.error.update": "Failed to update device",
+ "device.error.save": "Failed to save settings",
+ "device.error.clone_failed": "Failed to clone device",
+ "device_discovery.error.fill_all_fields": "Please fill in all fields",
+ "device_discovery.added": "Device added successfully",
+ "device_discovery.error.add_failed": "Failed to add device",
+ "calibration.error.load_failed": "Failed to load calibration",
+ "calibration.error.css_load_failed": "Failed to load color strip source",
+ "calibration.error.test_toggle_failed": "Failed to toggle test edge",
+ "calibration.error.save_failed": "Failed to save calibration",
+ "calibration.error.led_count_mismatch": "Total LEDs must equal the device LED count",
+ "calibration.error.led_count_exceeded": "Calibrated LEDs exceed the total LED count",
+ "calibration.mode.simple": "Simple",
+ "calibration.mode.advanced": "Advanced",
+ "calibration.switch_to_advanced": "Switch to Advanced",
+ "calibration.advanced.title": "Advanced Calibration",
+ "calibration.advanced.switch_to_simple": "Switch to Simple",
+ "calibration.advanced.lines_title": "Lines",
+ "calibration.advanced.canvas_hint": "Drag monitors to reposition. Click edges to select lines. Scroll to zoom, drag empty space to pan.",
+ "calibration.advanced.reset_view": "Reset view",
+ "calibration.advanced.line_properties": "Line Properties",
+ "calibration.advanced.picture_source": "Source:",
+ "calibration.advanced.picture_source.hint": "The picture source (monitor) this line samples from",
+ "calibration.advanced.edge": "Edge:",
+ "calibration.advanced.edge.hint": "Which screen edge to sample pixels from",
+ "calibration.advanced.led_count": "LEDs:",
+ "calibration.advanced.led_count.hint": "Number of LEDs mapped to this line",
+ "calibration.advanced.span_start": "Span Start:",
+ "calibration.advanced.span_start.hint": "Where sampling begins along the edge (0 = start, 1 = end). Use to cover only part of an edge.",
+ "calibration.advanced.span_end": "Span End:",
+ "calibration.advanced.span_end.hint": "Where sampling ends along the edge (0 = start, 1 = end). Together with Span Start, defines the active portion.",
+ "calibration.advanced.border_width": "Depth (px):",
+ "calibration.advanced.border_width.hint": "How many pixels deep from the edge to sample. Larger values capture more of the screen interior.",
+ "calibration.advanced.reverse": "Reverse",
+ "calibration.advanced.no_lines_warning": "Add at least one line",
+ "dashboard.error.automation_toggle_failed": "Failed to toggle automation",
+ "dashboard.error.start_failed": "Failed to start processing",
+ "dashboard.error.stop_failed": "Failed to stop processing",
+ "dashboard.error.stop_all": "Failed to stop all targets",
+ "target.error.editor_open_failed": "Failed to open target editor",
+ "target.error.start_failed": "Failed to start target",
+ "target.error.stop_failed": "Failed to stop target",
+ "target.error.clone_failed": "Failed to clone target",
+ "target.error.delete_failed": "Failed to delete target",
+ "targets.stop_all.button": "Stop All",
+ "targets.stop_all.none_running": "No targets are currently running",
+ "targets.stop_all.stopped": "Stopped {count} target(s)",
+ "targets.stop_all.error": "Failed to stop targets",
+ "audio_source.error.load": "Failed to load audio source",
+ "audio_template.error.clone_failed": "Failed to clone audio template",
+ "value_source.error.load": "Failed to load value source",
+ "color_strip.error.editor_open_failed": "Failed to open color strip editor",
+ "color_strip.error.clone_failed": "Failed to clone color strip source",
+ "color_strip.error.delete_failed": "Failed to delete color strip source",
+ "pattern.error.editor_open_failed": "Failed to open pattern template editor",
+ "pattern.error.clone_failed": "Failed to clone pattern template",
+ "pattern.error.delete_failed": "Failed to delete pattern template",
+ "pattern.error.capture_bg_failed": "Failed to capture background",
+ "stream.error.clone_picture_failed": "Failed to clone picture source",
+ "stream.error.clone_capture_failed": "Failed to clone capture template",
+ "stream.error.clone_pp_failed": "Failed to clone postprocessing template",
+ "kc_target.error.editor_open_failed": "Failed to open key colors editor",
+ "kc_target.error.clone_failed": "Failed to clone key colors target",
+ "kc_target.error.delete_failed": "Failed to delete key colors target",
+ "theme.switched.dark": "Switched to dark theme",
+ "theme.switched.light": "Switched to light theme",
+ "accent.color.updated": "Accent color updated",
+ "search.footer": "↑↓ navigate · Enter select · Esc close",
+ "sync_clock.group.title": "Sync Clocks",
+ "sync_clock.add": "Add Sync Clock",
+ "sync_clock.edit": "Edit Sync Clock",
+ "sync_clock.name": "Name:",
+ "sync_clock.name.placeholder": "Main Animation Clock",
+ "sync_clock.name.hint": "A descriptive name for this synchronization clock",
+ "sync_clock.speed": "Speed:",
+ "sync_clock.speed.hint": "Animation speed multiplier for all linked sources. 1.0 = normal, 2.0 = double speed, 0.5 = half speed.",
+ "sync_clock.description": "Description (optional):",
+ "sync_clock.description.placeholder": "Optional description",
+ "sync_clock.description.hint": "Optional notes about this clock's purpose",
+ "sync_clock.status.running": "Running",
+ "sync_clock.status.paused": "Paused",
+ "sync_clock.action.pause": "Pause",
+ "sync_clock.action.resume": "Resume",
+ "sync_clock.action.reset": "Reset",
+ "sync_clock.error.name_required": "Clock name is required",
+ "sync_clock.error.load": "Failed to load sync clock",
+ "sync_clock.created": "Sync clock created",
+ "sync_clock.updated": "Sync clock updated",
+ "sync_clock.deleted": "Sync clock deleted",
+ "sync_clock.paused": "Clock paused",
+ "sync_clock.resumed": "Clock resumed",
+ "sync_clock.reset_done": "Clock reset to zero",
+ "sync_clock.delete.confirm": "Delete this sync clock? Linked sources will lose synchronization and run at default speed.",
+ "sync_clock.elapsed": "Elapsed time",
+ "color_strip.clock": "Sync Clock:",
+ "color_strip.clock.hint": "Link to a sync clock to synchronize animation timing across sources. Speed is controlled on the clock.",
+ "graph.title": "Graph",
+ "graph.fit_all": "Fit all nodes",
+ "graph.zoom_in": "Zoom in",
+ "graph.zoom_out": "Zoom out",
+ "graph.search": "Search nodes",
+ "graph.search_placeholder": "Search entities...",
+ "graph.legend": "Legend",
+ "graph.minimap": "Minimap",
+ "graph.relayout": "Re-layout",
+ "graph.empty": "No entities yet",
+ "graph.empty.hint": "Create devices, sources, and targets to see them here.",
+ "graph.disconnect": "Disconnect",
+ "graph.connection_updated": "Connection updated",
+ "graph.connection_failed": "Failed to update connection",
+ "graph.connection_removed": "Connection removed",
+ "graph.disconnect_failed": "Failed to disconnect",
+ "graph.relayout_confirm": "Reset all manual node positions and re-layout the graph?",
+ "graph.fullscreen": "Toggle fullscreen",
+ "graph.add_entity": "Add entity",
+ "graph.color_picker": "Node color",
+ "graph.filter": "Filter nodes",
+ "graph.filter_placeholder": "Filter: name, type:x, tag:x",
+ "graph.filter_clear": "Clear filter",
+ "graph.filter_running": "Running",
+ "graph.filter_stopped": "Stopped",
+ "graph.filter_types": "Types",
+ "graph.filter_group.capture": "Capture",
+ "graph.filter_group.strip": "Color Strip",
+ "graph.filter_group.audio": "Audio",
+ "graph.filter_group.targets": "Targets",
+ "graph.filter_group.other": "Other",
+ "graph.bulk_delete_confirm": "Delete {count} selected entities?",
+ "graph.nothing_to_undo": "Nothing to undo",
+ "graph.nothing_to_redo": "Nothing to redo",
+ "graph.help_title": "Keyboard Shortcuts",
+ "graph.help.search": "Search",
+ "graph.help.filter": "Filter",
+ "graph.help.add": "Add entity",
+ "graph.help.shortcuts": "Shortcuts",
+ "graph.help.delete": "Delete / Detach",
+ "graph.help.select_all": "Select all",
+ "graph.help.undo": "Undo",
+ "graph.help.redo": "Redo",
+ "graph.help.fullscreen": "Fullscreen",
+ "graph.help.deselect": "Deselect",
+ "graph.help.navigate": "Navigate nodes",
+ "graph.help.click": "Click",
+ "graph.help.click_desc": "Select node",
+ "graph.help.dblclick": "Double-click",
+ "graph.help.dblclick_desc": "Zoom to node",
+ "graph.help.shift_click": "Shift+Click",
+ "graph.help.shift_click_desc": "Multi-select",
+ "graph.help.shift_drag": "Shift+Drag",
+ "graph.help.shift_drag_desc": "Rubber-band select",
+ "graph.help.drag_node": "Drag node",
+ "graph.help.drag_node_desc": "Reposition",
+ "graph.help.drag_port": "Drag port",
+ "graph.help.drag_port_desc": "Connect entities",
+ "graph.help.right_click": "Right-click edge",
+ "graph.help.right_click_desc": "Detach connection",
+ "graph.tooltip.fps": "FPS",
+ "graph.tooltip.errors": "Errors",
+ "graph.tooltip.uptime": "Uptime",
+ "automation.enabled": "Automation enabled",
+ "automation.disabled": "Automation disabled",
+ "scene_preset.activated": "Preset activated",
+ "scene_preset.used_by": "Used by %d automation(s)",
+ "settings.api_keys.label": "API Keys",
+ "settings.api_keys.hint": "API keys are defined in the server config file (config.yaml). Edit the file and restart the server to apply changes.",
+ "settings.api_keys.empty": "No API keys configured",
+ "settings.api_keys.load_error": "Failed to load API keys",
+ "settings.partial.label": "Partial Export / Import",
+ "settings.partial.hint": "Export or import a single entity type. Import replaces or merges existing data and restarts the server.",
+ "settings.partial.store.devices": "Devices",
+ "settings.partial.store.output_targets": "LED Targets",
+ "settings.partial.store.color_strip_sources": "Color Strips",
+ "settings.partial.store.picture_sources": "Picture Sources",
+ "settings.partial.store.audio_sources": "Audio Sources",
+ "settings.partial.store.audio_templates": "Audio Templates",
+ "settings.partial.store.capture_templates": "Capture Templates",
+ "settings.partial.store.postprocessing_templates": "Post-processing Templates",
+ "settings.partial.store.color_strip_processing_templates": "CSS Processing Templates",
+ "settings.partial.store.pattern_templates": "Pattern Templates",
+ "settings.partial.store.value_sources": "Value Sources",
+ "settings.partial.store.sync_clocks": "Sync Clocks",
+ "settings.partial.store.automations": "Automations",
+ "settings.partial.store.scene_presets": "Scene Presets",
+ "settings.partial.export_button": "Export",
+ "settings.partial.import_button": "Import from File",
+ "settings.partial.merge_label": "Merge (add/overwrite, keep existing)",
+ "settings.partial.export_success": "Exported successfully",
+ "settings.partial.export_error": "Export failed",
+ "settings.partial.import_success": "Imported successfully",
+ "settings.partial.import_error": "Import failed",
+ "settings.partial.import_confirm_replace": "This will REPLACE all {store} data and restart the server. Continue?",
+ "settings.partial.import_confirm_merge": "This will MERGE into existing {store} data and restart the server. Continue?",
+ "section.empty.devices": "No devices yet. Click + to add one.",
+ "section.empty.targets": "No LED targets yet. Click + to add one.",
+ "section.empty.kc_targets": "No key color targets yet. Click + to add one.",
+ "section.empty.pattern_templates": "No pattern templates yet. Click + to add one.",
+ "section.empty.picture_sources": "No sources yet. Click + to add one.",
+ "section.empty.capture_templates": "No capture templates yet. Click + to add one.",
+ "section.empty.pp_templates": "No post-processing templates yet. Click + to add one.",
+ "section.empty.audio_sources": "No audio sources yet. Click + to add one.",
+ "section.empty.audio_templates": "No audio templates yet. Click + to add one.",
+ "section.empty.color_strips": "No color strips yet. Click + to add one.",
+ "section.empty.value_sources": "No value sources yet. Click + to add one.",
+ "section.empty.sync_clocks": "No sync clocks yet. Click + to add one.",
+ "section.empty.cspt": "No CSS processing templates yet. Click + to add one.",
+ "section.empty.automations": "No automations yet. Click + to add one.",
+ "section.empty.scenes": "No scene presets yet. Click + to add one.",
+ "bulk.select": "Select",
+ "bulk.cancel": "Cancel",
+ "bulk.selected_count.one": "{count} selected",
+ "bulk.selected_count.other": "{count} selected",
+ "bulk.select_all": "Select all",
+ "bulk.deselect_all": "Deselect all",
+ "bulk.delete": "Delete",
+ "bulk.start": "Start",
+ "bulk.stop": "Stop",
+ "bulk.enable": "Enable",
+ "bulk.disable": "Disable",
+ "bulk.confirm_delete.one": "Delete {count} item?",
+ "bulk.confirm_delete.other": "Delete {count} items?",
+ "color_strip": {
+ "notification": {
+ "search_apps": "Search notification apps…"
+ }
+ }
+}
\ No newline at end of file
diff --git a/server/src/wled_controller/static/locales/ru.json b/server/src/wled_controller/static/locales/ru.json
index 7b851d9..b431c25 100644
--- a/server/src/wled_controller/static/locales/ru.json
+++ b/server/src/wled_controller/static/locales/ru.json
@@ -1,1749 +1,1750 @@
{
- "app.title": "LED Grab",
- "app.version": "Версия:",
- "app.api_docs": "Документация API",
- "app.connection_lost": "Сервер недоступен",
- "app.connection_retrying": "Попытка переподключения…",
- "demo.badge": "ДЕМО",
- "demo.banner": "Вы в демо-режиме — все устройства и данные виртуальные. Реальное оборудование не используется.",
- "theme.toggle": "Переключить тему",
- "bg.anim.toggle": "Анимированный фон",
- "accent.title": "Цвет акцента",
- "accent.custom": "Свой",
- "accent.reset": "Сброс",
- "locale.change": "Изменить язык",
- "auth.login": "Войти",
- "auth.logout": "Выйти",
- "auth.authenticated": "● Авторизован",
- "auth.title": "Вход в LED Grab",
- "auth.message": "Пожалуйста, введите ваш API ключ для аутентификации и доступа к LED Grab.",
- "auth.label": "API Ключ:",
- "auth.placeholder": "Введите ваш API ключ...",
- "auth.hint": "Ваш API ключ будет безопасно сохранен в локальном хранилище браузера.",
- "auth.button.cancel": "Отмена",
- "auth.button.login": "Войти",
- "auth.error.required": "Пожалуйста, введите API ключ",
- "auth.success": "Вход выполнен успешно!",
- "auth.logout.confirm": "Вы уверены, что хотите выйти?",
- "auth.logout.success": "Выход выполнен успешно",
- "auth.please_login": "Пожалуйста, войдите для просмотра",
- "auth.session_expired": "Ваша сессия истекла или API ключ недействителен. Пожалуйста, войдите снова.",
- "auth.toggle_password": "Показать/скрыть пароль",
- "auth.prompt_enter": "Enter your API key:",
- "auth.prompt_update": "Current API key is set. Enter new key to update or leave blank to remove:",
- "api_key.login": "Войти",
- "displays.title": "Доступные Дисплеи",
- "displays.layout": "Дисплеи",
- "displays.information": "Информация о Дисплеях",
- "displays.legend.primary": "Основной Дисплей",
- "displays.legend.secondary": "Вторичный Дисплей",
- "displays.badge.primary": "Основной",
- "displays.badge.secondary": "Вторичный",
- "displays.resolution": "Разрешение:",
- "displays.refresh_rate": "Частота Обновления:",
- "displays.position": "Позиция:",
- "displays.index": "Индекс Дисплея:",
- "displays.loading": "Загрузка дисплеев...",
- "displays.none": "Нет доступных дисплеев",
- "displays.failed": "Не удалось загрузить дисплеи",
- "displays.picker.title": "Выберите Дисплей",
- "displays.picker.title.device": "Выберите Устройство",
- "displays.picker.select": "Выберите дисплей...",
- "displays.picker.click_to_select": "Нажмите, чтобы выбрать этот дисплей",
- "displays.picker.adb_connect": "Подключить ADB устройство",
- "displays.picker.adb_connect.placeholder": "IP адрес (напр. 192.168.2.201)",
- "displays.picker.adb_connect.button": "Подключить",
- "displays.picker.adb_connect.success": "Устройство подключено",
- "displays.picker.adb_connect.error": "Не удалось подключить устройство",
- "displays.picker.adb_disconnect": "Отключить",
- "displays.picker.no_android": "Android устройства не найдены. Подключите по USB или введите IP выше.",
- "templates.title": "Шаблоны Движков",
- "templates.description": "Шаблоны захвата определяют, как захватывается экран. Каждый шаблон использует определённый движок захвата (MSS, DXcam, WGC) с настраиваемыми параметрами. Назначайте шаблоны устройствам для оптимальной производительности.",
- "templates.loading": "Загрузка шаблонов...",
- "templates.empty": "Шаблоны захвата не настроены",
- "templates.add": "Добавить Шаблон Движка",
- "templates.edit": "Редактировать Шаблон Движка",
- "templates.name": "Имя Шаблона:",
- "templates.name.placeholder": "Мой Пользовательский Шаблон",
- "templates.description.label": "Описание (необязательно):",
- "templates.description.placeholder": "Опишите этот шаблон...",
- "templates.engine": "Движок Захвата:",
- "templates.engine.hint": "Выберите технологию захвата экрана",
- "templates.engine.select": "Выберите движок...",
- "templates.engine.unavailable": "Недоступен",
- "templates.engine.unavailable.hint": "Этот движок недоступен в вашей системе",
- "templates.engine.mss.desc": "Кроссплатформенный, чистый Python",
- "templates.engine.dxcam.desc": "DirectX, низкая задержка",
- "templates.engine.bettercam.desc": "DirectX, высокая производительность",
- "templates.engine.camera.desc": "Захват USB/IP камеры",
- "templates.engine.scrcpy.desc": "Зеркалирование экрана Android",
- "templates.engine.wgc.desc": "Windows Graphics Capture",
- "templates.config": "Конфигурация",
- "templates.config.show": "Показать конфигурацию",
- "templates.config.none": "Нет дополнительных настроек",
- "templates.config.default": "По умолчанию",
- "templates.config.camera_backend.auto": "Автовыбор лучшего бэкенда",
- "templates.config.camera_backend.dshow": "Windows DirectShow",
- "templates.config.camera_backend.msmf": "Windows Media Foundation",
- "templates.config.camera_backend.v4l2": "Linux Video4Linux2",
- "templates.created": "Шаблон успешно создан",
- "templates.updated": "Шаблон успешно обновлён",
- "templates.deleted": "Шаблон успешно удалён",
- "templates.delete.confirm": "Вы уверены, что хотите удалить этот шаблон?",
- "templates.error.load": "Не удалось загрузить шаблоны",
- "templates.error.engines": "Не удалось загрузить движки",
- "templates.error.required": "Пожалуйста, заполните все обязательные поля",
- "templates.error.delete": "Не удалось удалить шаблон",
- "templates.test.title": "Тест Захвата",
- "templates.test.description": "Протестируйте этот шаблон перед сохранением, чтобы увидеть предпросмотр захвата и метрики производительности.",
- "templates.test.display": "Дисплей:",
- "templates.test.display.select": "Выберите дисплей...",
- "templates.test.duration": "Длительность Захвата (с):",
- "templates.test.border_width": "Ширина Границы (px):",
- "templates.test.run": "Запустить",
- "templates.test.running": "Выполняется тест...",
- "templates.test.results.preview": "Полный Предпросмотр Захвата",
- "templates.test.results.borders": "Извлечение Границ",
- "templates.test.results.top": "Сверху",
- "templates.test.results.right": "Справа",
- "templates.test.results.bottom": "Снизу",
- "templates.test.results.left": "Слева",
- "templates.test.results.performance": "Производительность",
- "templates.test.results.capture_time": "Захват",
- "templates.test.results.extraction_time": "Извлечение",
- "templates.test.results.total_time": "Всего",
- "templates.test.results.max_fps": "Макс. FPS",
- "templates.test.results.duration": "Длительность",
- "templates.test.results.frame_count": "Кадры",
- "templates.test.results.actual_fps": "Факт. FPS",
- "templates.test.results.avg_capture_time": "Средн. Захват",
- "templates.test.results.resolution": "Разрешение:",
- "templates.test.error.no_engine": "Пожалуйста, выберите движок захвата",
- "templates.test.error.no_display": "Пожалуйста, выберите дисплей",
- "templates.test.error.failed": "Тест не удался",
- "devices.title": "Устройства",
- "device.select_type": "Выберите тип устройства",
- "devices.add": "Добавить Новое Устройство",
- "devices.loading": "Загрузка устройств...",
- "devices.none": "Устройства не настроены",
- "devices.failed": "Не удалось загрузить устройства",
- "devices.wled_config": "Конфигурация WLED:",
- "devices.wled_note": "Настройте ваше WLED устройство (эффекты, сегменты, порядок цветов, ограничения питания и т.д.) используя",
- "devices.wled_link": "официальное приложение WLED",
- "devices.wled_note_or": "или встроенный",
- "devices.wled_webui_link": "веб-интерфейс WLED",
- "devices.wled_note_webui": "(откройте IP устройства в браузере).",
- "devices.wled_note2": "Этот контроллер отправляет данные о цвете пикселей и управляет яркостью для каждого устройства.",
- "device.scan": "Автопоиск",
- "device.scan.empty": "Устройства не найдены",
- "device.scan.error": "Ошибка сканирования сети",
- "device.scan.already_added": "Уже добавлено",
- "device.scan.selected": "Устройство выбрано",
- "device.type": "Тип устройства:",
- "device.type.hint": "Выберите тип LED контроллера",
- "device.type.wled": "WLED",
- "device.type.wled.desc": "WiFi LED контроллер по HTTP/UDP",
- "device.type.adalight": "Adalight",
- "device.type.adalight.desc": "Серийный протокол для Arduino",
- "device.type.ambiled": "AmbiLED",
- "device.type.ambiled.desc": "Серийный протокол AmbiLED",
- "device.type.mqtt": "MQTT",
- "device.type.mqtt.desc": "Отправка LED данных через MQTT брокер",
- "device.type.ws": "WebSocket",
- "device.type.ws.desc": "Стриминг LED данных через WebSocket",
- "device.type.openrgb": "OpenRGB",
- "device.type.openrgb.desc": "Управление RGB через OpenRGB",
- "device.type.dmx": "DMX",
- "device.type.dmx.desc": "Art-Net / sACN (E1.31) сценическое освещение",
- "device.type.mock": "Mock",
- "device.type.mock.desc": "Виртуальное устройство для тестов",
- "device.type.espnow": "ESP-NOW",
- "device.type.espnow.desc": "Ultra-low-latency via ESP32 gateway",
- "device.type.hue": "Philips Hue",
- "device.type.hue.desc": "Hue Entertainment API streaming",
- "device.type.usbhid": "USB HID",
- "device.type.usbhid.desc": "USB RGB peripherals (keyboards, mice)",
- "device.type.spi": "SPI Direct",
- "device.type.spi.desc": "Raspberry Pi GPIO/SPI LED strips",
- "device.type.chroma": "Razer Chroma",
- "device.type.chroma.desc": "Razer peripherals via Chroma SDK",
- "device.type.gamesense": "SteelSeries",
- "device.type.gamesense.desc": "SteelSeries peripherals via GameSense",
- "device.chroma.device_type": "Peripheral Type:",
- "device.chroma.device_type.hint": "Which Razer peripheral to control via Chroma SDK",
- "device.gamesense.device_type": "Peripheral Type:",
- "device.gamesense.device_type.hint": "Which SteelSeries peripheral to control via GameSense",
- "device.espnow.peer_mac": "Peer MAC:",
- "device.espnow.peer_mac.hint": "MAC address of the remote ESP32 receiver (e.g. AA:BB:CC:DD:EE:FF)",
- "device.espnow.channel": "WiFi Channel:",
- "device.espnow.channel.hint": "WiFi channel (1-14). Must match the receiver's channel.",
- "device.hue.url": "Bridge IP:",
- "device.hue.url.hint": "IP address of your Hue bridge",
- "device.hue.username": "Bridge Username:",
- "device.hue.username.hint": "Hue bridge application key from pairing",
- "device.hue.client_key": "Client Key:",
- "device.hue.client_key.hint": "Entertainment API client key (hex string from pairing)",
- "device.hue.group_id": "Entertainment Group:",
- "device.hue.group_id.hint": "Entertainment configuration ID from your Hue bridge",
- "device.usbhid.url": "VID:PID:",
- "device.usbhid.url.hint": "USB Vendor:Product ID in hex (e.g. 1532:0084)",
- "device.spi.url": "GPIO/SPI Path:",
- "device.spi.url.hint": "GPIO pin or SPI device path (e.g. spi://gpio:18)",
- "device.spi.speed": "SPI Speed (Hz):",
- "device.spi.speed.hint": "SPI clock speed. 800000 Hz for WS2812, 2400000 Hz for APA102.",
- "device.spi.led_type": "LED Chipset:",
- "device.spi.led_type.hint": "Type of addressable LED strip connected to the GPIO/SPI pin",
- "device.spi.led_type.ws2812b.desc": "Most common, 800 KHz data, 3-wire RGB",
- "device.spi.led_type.ws2812.desc": "Original WS2812, 800 KHz, 3-wire RGB",
- "device.spi.led_type.ws2811.desc": "External driver IC, 400 KHz, 12V strips",
- "device.spi.led_type.sk6812.desc": "Samsung LED, 800 KHz, 3-wire RGB",
- "device.spi.led_type.sk6812_rgbw.desc": "SK6812 with dedicated white channel",
- "device.gamesense.peripheral.keyboard": "Keyboard",
- "device.gamesense.peripheral.keyboard.desc": "Per-key RGB illumination",
- "device.gamesense.peripheral.mouse": "Mouse",
- "device.gamesense.peripheral.mouse.desc": "Mouse RGB zones",
- "device.gamesense.peripheral.headset": "Headset",
- "device.gamesense.peripheral.headset.desc": "Headset earcup lighting",
- "device.gamesense.peripheral.mousepad": "Mousepad",
- "device.gamesense.peripheral.mousepad.desc": "Mousepad edge lighting zones",
- "device.gamesense.peripheral.indicator": "Indicator",
- "device.gamesense.peripheral.indicator.desc": "OLED/LED status indicator",
- "device.dmx_protocol": "Протокол DMX:",
- "device.dmx_protocol.hint": "Art-Net использует UDP порт 6454, sACN (E1.31) — UDP порт 5568",
- "device.dmx_protocol.artnet.desc": "UDP unicast, порт 6454",
- "device.dmx_protocol.sacn.desc": "Multicast/unicast, порт 5568",
- "device.dmx_start_universe": "Начальный Universe:",
- "device.dmx_start_universe.hint": "Первый DMX-юниверс (0-32767). Дополнительные юниверсы используются автоматически при >170 светодиодах.",
- "device.dmx_start_channel": "Начальный канал:",
- "device.dmx_start_channel.hint": "Первый DMX-канал в юниверсе (1-512)",
- "device.dmx.url": "IP адрес:",
- "device.dmx.url.hint": "IP адрес DMX-узла (напр. 192.168.1.50)",
- "device.dmx.url.placeholder": "192.168.1.50",
- "device.serial_port": "Серийный порт:",
- "device.serial_port.hint": "Выберите COM порт устройства Adalight",
- "device.serial_port.none": "Серийные порты не найдены",
- "device.serial_port.select": "Выберите порт...",
- "device.led_count_manual.hint": "Количество светодиодов на ленте (должно совпадать с вашим скетчем Arduino)",
- "device.baud_rate": "Скорость порта:",
- "device.baud_rate.hint": "Скорость серийного соединения. Выше = больше FPS, но требует соответствия скетчу Arduino.",
- "device.led_type": "Тип LED:",
- "device.led_type.hint": "RGB (3 канала) или RGBW (4 канала с выделенным белым)",
- "device.send_latency": "Задержка отправки (мс):",
- "device.send_latency.hint": "Имитация сетевой/серийной задержки на кадр в миллисекундах",
- "device.css_processing_template": "Шаблон Обработки Полос:",
- "device.css_processing_template.hint": "Шаблон обработки по умолчанию, применяемый ко всем цветовым полосам на этом устройстве",
- "device.mqtt_topic": "MQTT Топик:",
- "device.mqtt_topic.hint": "MQTT топик для публикации пиксельных данных (напр. mqtt://ledgrab/device/name)",
- "device.mqtt_topic.placeholder": "mqtt://ledgrab/device/гостиная",
- "device.ws_url": "URL подключения:",
- "device.ws_url.hint": "WebSocket URL для подключения клиентов и получения LED данных",
- "device.openrgb.url": "OpenRGB URL:",
- "device.openrgb.url.hint": "Адрес сервера OpenRGB (напр. openrgb://localhost:6742/0)",
- "device.openrgb.zone": "Зоны:",
- "device.openrgb.zone.hint": "Выберите зоны LED для управления (оставьте все неотмеченными для всех зон)",
- "device.openrgb.zone.loading": "Загрузка зон…",
- "device.openrgb.zone.error": "Не удалось загрузить зоны",
- "device.openrgb.mode": "Режим зон:",
- "device.openrgb.mode.hint": "Объединённый — все зоны как одна непрерывная LED-лента. Раздельный — каждая зона независимо отображает полный эффект.",
- "device.openrgb.mode.combined": "Объединённая лента",
- "device.openrgb.mode.separate": "Независимые зоны",
- "device.openrgb.added_multiple": "Добавлено {count} устройств",
- "device.type.openrgb": "OpenRGB",
- "device.url.hint": "IP адрес или имя хоста устройства (напр. http://192.168.1.100)",
- "device.name": "Имя Устройства:",
- "device.name.placeholder": "ТВ в Гостиной",
- "device.url": "URL:",
- "device.url.placeholder": "http://192.168.1.100",
- "device.led_count": "Количество Светодиодов:",
- "device.led_count.hint": "Количество светодиодов, настроенных в устройстве",
- "device.led_count.hint.auto": "Автоматически определяется из устройства",
- "device.button.add": "Добавить Устройство",
- "device.button.start": "Запустить",
- "device.button.stop": "Остановить",
- "device.button.settings": "Основные настройки",
- "device.button.capture_settings": "Настройки захвата",
- "device.button.calibrate": "Калибровка",
- "device.button.remove": "Удалить",
- "device.button.webui": "Открыть веб-интерфейс устройства",
- "device.button.power_off": "Выключить",
- "device.button.ping": "Пинг устройства",
- "device.ping.online": "Онлайн ({ms}мс)",
- "device.ping.offline": "Устройство недоступно",
- "device.ping.error": "Ошибка пинга",
- "device.power.off_success": "Устройство выключено",
- "device.status.connected": "Подключено",
- "device.status.disconnected": "Отключено",
- "device.status.error": "Ошибка",
- "device.status.processing": "Обработка",
- "device.status.idle": "Ожидание",
- "device.fps": "FPS:",
- "device.display": "Дисплей:",
- "device.remove.confirm": "Вы уверены, что хотите удалить это устройство?",
- "device.added": "Устройство успешно добавлено",
- "device.removed": "Устройство успешно удалено",
- "device.started": "Обработка запущена",
- "device.stopped": "Обработка остановлена",
- "device.metrics.actual_fps": "Факт. FPS",
- "device.metrics.current_fps": "Текущ. FPS",
- "device.metrics.target_fps": "Целев. FPS",
- "device.metrics.potential_fps": "Потенц. FPS",
- "device.metrics.frames": "Кадры",
- "device.metrics.frames_skipped": "Пропущено",
- "device.metrics.keepalive": "Keepalive",
- "device.metrics.errors": "Ошибки",
- "device.metrics.uptime": "Время работы",
- "device.metrics.timing": "Тайминг пайплайна:",
- "device.metrics.device_fps": "Частота обновления устройства",
- "device.health.online": "Онлайн",
- "device.health.offline": "Недоступен",
- "device.health.streaming_unreachable": "Недоступен во время стриминга",
- "device.health.checking": "Проверка...",
- "device.last_seen.label": "Последний раз",
- "device.last_seen.just_now": "только что",
- "device.last_seen.seconds": "%d с назад",
- "device.last_seen.minutes": "%d мин назад",
- "device.last_seen.hours": "%d ч назад",
- "device.last_seen.days": "%d д назад",
- "device.tutorial.start": "Начать обучение",
- "device.tip.metadata": "Информация об устройстве (кол-во LED, тип, цветовые каналы) определяется автоматически",
- "device.tip.brightness": "Перетащите для регулировки яркости",
- "device.tip.start": "Запуск или остановка захвата экрана",
- "device.tip.settings": "Основные настройки устройства (имя, URL, интервал проверки)",
- "device.tip.capture_settings": "Настройки захвата (дисплей, шаблон захвата)",
- "device.tip.calibrate": "Калибровка позиций LED, направления и зоны покрытия",
- "device.tip.webui": "Открыть встроенный веб-интерфейс устройства для расширенной настройки",
- "device.tip.add": "Нажмите, чтобы добавить новое LED устройство",
- "settings.title": "Настройки",
- "settings.tab.general": "Основные",
- "settings.tab.backup": "Бэкап",
- "settings.tab.mqtt": "MQTT",
- "settings.logs.open_viewer": "Открыть логи",
- "settings.external_url.label": "Внешний URL",
- "settings.external_url.hint": "Если указан, этот базовый URL используется в URL-ах вебхуков и других пользовательских ссылках вместо автоопределённого локального IP. Пример: https://myserver.example.com:8080",
- "settings.external_url.placeholder": "https://myserver.example.com:8080",
- "settings.external_url.save": "Сохранить",
- "settings.external_url.saved": "Внешний URL сохранён",
- "settings.external_url.save_error": "Не удалось сохранить внешний URL",
- "settings.general.title": "Основные Настройки",
- "settings.capture.title": "Настройки Захвата",
- "settings.capture.saved": "Настройки захвата обновлены",
- "settings.capture.failed": "Не удалось сохранить настройки захвата",
- "settings.brightness": "Яркость:",
- "settings.brightness.hint": "Общая яркость для этого устройства (0-100%)",
- "settings.url.hint": "IP адрес или имя хоста устройства",
- "settings.display_index": "Дисплей:",
- "settings.display_index.hint": "Какой экран захватывать для этого устройства",
- "settings.fps": "Целевой FPS:",
- "settings.fps.hint": "Целевая частота кадров (10-90)",
- "settings.capture_template": "Шаблон Движка:",
- "settings.capture_template.hint": "Движок захвата экрана и конфигурация для этого устройства",
- "settings.button.cancel": "Отмена",
- "settings.health_interval": "Интервал Проверки (с):",
- "settings.health_interval.hint": "Как часто проверять статус устройства (5-600 секунд)",
- "settings.auto_shutdown": "Авто-восстановление:",
- "settings.auto_shutdown.hint": "Восстанавливать устройство в режим ожидания при остановке целей или сервера",
- "settings.button.save": "Сохранить Изменения",
- "settings.saved": "Настройки успешно сохранены",
- "settings.failed": "Не удалось сохранить настройки",
- "calibration.title": "Калибровка Светодиодов",
- "calibration.tip.led_count": "Укажите количество LED на каждой стороне",
- "calibration.tip.start_corner": "Нажмите на угол для выбора стартовой позиции",
- "calibration.tip.direction": "Переключение направления ленты (по часовой / против часовой)",
- "calibration.tip.offset": "Смещение LED — расстояние от LED 0 до стартового угла",
- "calibration.tip.span": "Перетащите зелёные полосы для настройки зоны покрытия",
- "calibration.tip.test": "Нажмите на край для теста LED",
- "calibration.tip.overlay": "Включите оверлей для отображения позиций и нумерации LED на мониторе",
- "calibration.tip.toggle_inputs": "Нажмите на общее количество LED для скрытия боковых полей",
- "calibration.tip.border_width": "Сколько пикселей от края экрана использовать для цветов LED",
- "calibration.tip.skip_leds_start": "Пропуск LED в начале ленты — пропущенные LED остаются выключенными",
- "calibration.tip.skip_leds_end": "Пропуск LED в конце ленты — пропущенные LED остаются выключенными",
- "tour.welcome": "Добро пожаловать в LED Grab! Этот краткий тур познакомит вас с интерфейсом. Используйте стрелки или кнопки для навигации.",
- "tour.dashboard": "Дашборд — обзор запущенных целей, автоматизаций и состояния устройств.",
- "tour.targets": "Цели — добавляйте WLED-устройства, настраивайте LED-цели с захватом и калибровкой.",
- "tour.sources": "Источники — управление шаблонами захвата, источниками изображений, звука и цветовых полос.",
- "tour.graph": "Граф — визуальный обзор всех сущностей и их связей. Перетаскивайте порты для соединения, правый клик по связям для отключения.",
- "tour.automations": "Автоматизации — автоматизируйте переключение сцен по расписанию, звуку или значениям.",
- "tour.settings": "Настройки — резервное копирование и восстановление конфигурации.",
- "tour.api": "API Документация — интерактивная документация REST API на базе Swagger.",
- "tour.search": "Поиск — быстрый поиск и переход к любому объекту по Ctrl+K.",
- "tour.theme": "Тема — переключение между тёмной и светлой темой.",
- "tour.accent": "Цвет акцента — настройте цвет интерфейса по своему вкусу.",
- "tour.language": "Язык — выберите предпочитаемый язык интерфейса.",
- "tour.restart": "Запустить тур заново",
- "tour.dash.perf": "Производительность — графики FPS в реальном времени, метрики задержки и интервал опроса.",
- "tour.dash.running": "Запущенные цели — метрики стриминга и быстрая остановка.",
- "tour.dash.stopped": "Остановленные цели — готовы к запуску одним нажатием.",
- "tour.dash.automations": "Автоматизации — статус активных автоматизаций и быстрое включение/выключение.",
- "tour.tgt.led_tab": "LED — стандартные LED-цели с настройкой устройств и цветовых полос.",
- "tour.tgt.devices": "Устройства — ваши LED-контроллеры, найденные в сети.",
- "tour.tgt.css": "Цветовые полосы — определите, как области экрана соответствуют сегментам LED.",
- "tour.tgt.targets": "LED-цели — объедините устройство, цветовую полосу и источник захвата для стриминга.",
- "tour.tgt.kc_tab": "Key Colors — альтернативный тип цели с подбором цветов вместо пиксельного маппинга.",
- "tour.src.raw": "Raw — источники захвата экрана с ваших дисплеев.",
- "tour.src.templates": "Шаблоны захвата — переиспользуемые конфигурации (разрешение, FPS, обрезка).",
- "tour.src.static": "Статичные изображения — тестируйте настройку с файлами изображений.",
- "tour.src.processed": "Обработка — применяйте эффекты: размытие, яркость, цветокоррекция.",
- "tour.src.color_strip": "Цветовые полосы — определяют, как области экрана сопоставляются с LED-сегментами.",
- "tour.src.audio": "Аудио — анализ микрофона или системного звука для реактивных LED-эффектов.",
- "tour.src.value": "Значения — числовые источники данных для условий автоматизаций.",
- "tour.src.sync": "Синхро-часы — общие таймеры для синхронизации анимаций между несколькими источниками.",
- "tour.auto.list": "Автоматизации — автоматизируйте активацию сцен по времени, звуку или значениям.",
- "tour.auto.add": "Нажмите + для создания новой автоматизации с условиями и сценой для активации.",
- "tour.auto.card": "Каждая карточка показывает статус автоматизации, условия и кнопки управления.",
- "tour.auto.scenes_list": "Сцены — сохранённые состояния системы, которые автоматизации могут активировать или вы можете применить вручную.",
- "tour.auto.scenes_add": "Нажмите + для захвата текущего состояния системы как нового пресета сцены.",
- "tour.auto.scenes_card": "Каждая карточка сцены показывает количество целей/устройств. Нажмите для редактирования, перезахвата или активации.",
- "calibration.tutorial.start": "Начать обучение",
- "calibration.overlay_toggle": "Оверлей",
- "calibration.start_position": "Начальная Позиция:",
- "calibration.position.bottom_left": "Нижний Левый",
- "calibration.position.bottom_right": "Нижний Правый",
- "calibration.position.top_left": "Верхний Левый",
- "calibration.position.top_right": "Верхний Правый",
- "calibration.direction": "Направление:",
- "calibration.direction.clockwise": "По Часовой Стрелке",
- "calibration.direction.counterclockwise": "Против Часовой Стрелки",
- "calibration.leds.top": "Светодиодов Сверху:",
- "calibration.leds.right": "Светодиодов Справа:",
- "calibration.leds.bottom": "Светодиодов Снизу:",
- "calibration.leds.left": "Светодиодов Слева:",
- "calibration.offset": "Смещение LED:",
- "calibration.offset.hint": "Расстояние от физического LED 0 до стартового угла (по направлению ленты)",
- "calibration.skip_start": "Пропуск LED (начало):",
- "calibration.skip_start.hint": "Количество LED, которые будут выключены в начале ленты (0 = нет)",
- "calibration.skip_end": "Пропуск LED (конец):",
- "calibration.skip_end.hint": "Количество LED, которые будут выключены в конце ленты (0 = нет)",
- "calibration.border_width": "Граница (px):",
- "calibration.border_width.hint": "Сколько пикселей от края экрана выбирать для цвета LED (1-100)",
- "calibration.button.cancel": "Отмена",
- "calibration.button.save": "Сохранить",
- "calibration.saved": "Калибровка успешно сохранена",
- "calibration.failed": "Не удалось сохранить калибровку",
- "server.healthy": "Сервер онлайн",
- "server.offline": "Сервер офлайн",
- "error.unauthorized": "Не авторизован - пожалуйста, войдите",
- "error.network": "Сетевая ошибка",
- "error.unknown": "Произошла ошибка",
- "modal.discard_changes": "У вас есть несохранённые изменения. Отменить их?",
- "confirm.title": "Подтверждение",
- "confirm.yes": "Да",
- "confirm.no": "Нет",
- "confirm.stop_all": "Остановить все запущенные цели?",
- "confirm.turn_off_device": "Выключить это устройство?",
- "common.loading": "Загрузка...",
- "common.delete": "Удалить",
- "common.edit": "Редактировать",
- "common.clone": "Клонировать",
- "common.none": "Нет",
- "common.none_no_cspt": "Нет (без шаблона обработки)",
- "common.none_no_input": "Нет (без источника)",
- "common.none_own_speed": "Нет (своя скорость)",
- "common.undo": "Отменить",
- "validation.required": "Обязательное поле",
- "bulk.processing": "Обработка…",
- "api.error.timeout": "Превышено время ожидания — попробуйте снова",
- "api.error.network": "Ошибка сети — проверьте подключение",
- "palette.search": "Поиск…",
- "section.filter.placeholder": "Фильтр...",
- "section.filter.reset": "Очистить фильтр",
- "tags.label": "Теги",
- "tags.hint": "Назначьте теги для группировки и фильтрации карточек",
- "tags.placeholder": "Добавить тег...",
- "section.expand_all": "Развернуть все секции",
- "section.collapse_all": "Свернуть все секции",
- "streams.title": "Источники",
- "streams.description": "Источники определяют конвейер захвата. Сырой источник захватывает экран с помощью шаблона захвата. Обработанный источник применяет постобработку к другому источнику. Назначайте источники устройствам.",
- "streams.group.raw": "Источники",
- "streams.group.raw_templates": "Шаблоны движка",
- "streams.group.processed": "Источники",
- "streams.group.proc_templates": "Шаблоны фильтров",
- "streams.group.css_processing": "Шаблоны Обработки",
- "streams.group.color_strip": "Цветовые Полосы",
- "streams.group.audio": "Аудио",
- "streams.group.audio_templates": "Аудио шаблоны",
- "streams.section.streams": "Источники",
- "streams.add": "Добавить Источник",
- "streams.add.raw": "Добавить Захват Экрана",
- "streams.add.processed": "Добавить Обработанный",
- "streams.edit": "Редактировать Источник",
- "streams.edit.raw": "Редактировать Захват Экрана",
- "streams.edit.processed": "Редактировать Обработанный Источник",
- "streams.name": "Имя Источника:",
- "streams.name.placeholder": "Мой Источник",
- "streams.type": "Тип:",
- "streams.type.raw": "Захват экрана",
- "streams.type.processed": "Обработанный",
- "streams.display": "Дисплей:",
- "streams.display.hint": "Какой экран захватывать",
- "streams.capture_template": "Шаблон Движка:",
- "streams.capture_template.hint": "Шаблон движка, определяющий способ захвата экрана",
- "streams.target_fps": "Целевой FPS:",
- "streams.target_fps.hint": "Целевое количество кадров в секунду (1-90)",
- "streams.source": "Источник:",
- "streams.source.hint": "Источник, к которому применяются фильтры обработки",
- "streams.pp_template": "Шаблон Фильтра:",
- "streams.pp_template.hint": "Шаблон фильтра для применения к источнику",
- "streams.description_label": "Описание (необязательно):",
- "streams.description_placeholder": "Опишите этот источник...",
- "streams.created": "Источник успешно создан",
- "streams.updated": "Источник успешно обновлён",
- "streams.deleted": "Источник успешно удалён",
- "streams.delete.confirm": "Вы уверены, что хотите удалить этот источник?",
- "streams.modal.loading": "Загрузка...",
- "streams.error.load": "Не удалось загрузить источники",
- "streams.error.required": "Пожалуйста, заполните все обязательные поля",
- "streams.error.delete": "Не удалось удалить источник",
- "streams.test.title": "Тест Источника",
- "streams.test.run": "Запустить",
- "streams.test.running": "Тестирование источника...",
- "streams.test.duration": "Длительность Захвата (с):",
- "streams.test.error.failed": "Тест источника не удался",
- "postprocessing.title": "Шаблоны Фильтров",
- "postprocessing.description": "Шаблоны обработки определяют фильтры изображений и цветокоррекцию. Назначайте их обработанным источникам для единообразной постобработки на всех устройствах.",
- "postprocessing.add": "Добавить Шаблон Фильтра",
- "postprocessing.edit": "Редактировать Шаблон Фильтра",
- "postprocessing.name": "Имя Шаблона:",
- "postprocessing.name.placeholder": "Мой Шаблон Фильтра",
- "filters.select_type": "Выберите тип фильтра...",
- "filters.add": "Добавить фильтр",
- "filters.remove": "Удалить",
- "filters.drag_to_reorder": "Перетащите для изменения порядка",
- "filters.empty": "Фильтры не добавлены. Используйте селектор ниже для добавления.",
- "filters.brightness": "Яркость",
- "filters.brightness.desc": "Регулировка общей яркости изображения",
- "filters.saturation": "Насыщенность",
- "filters.saturation.desc": "Усиление или снижение интенсивности цвета",
- "filters.gamma": "Гамма",
- "filters.gamma.desc": "Нелинейная коррекция кривой яркости",
- "filters.downscaler": "Уменьшение",
- "filters.downscaler.desc": "Снижение разрешения для быстрой обработки",
- "filters.pixelate": "Пикселизация",
- "filters.pixelate.desc": "Мозаичное усреднение блоков",
- "filters.auto_crop": "Авто Обрезка",
- "filters.auto_crop.desc": "Удаление чёрных полос из леттербокса",
- "filters.flip": "Отражение",
- "filters.flip.desc": "Зеркальное отражение по горизонтали или вертикали",
- "filters.color_correction": "Цветокоррекция",
- "filters.color_correction.desc": "Баланс белого и цветовая температура",
- "filters.filter_template": "Шаблон фильтров",
- "filters.filter_template.desc": "Встроить другой шаблон обработки",
- "filters.css_filter_template": "Шаблон Фильтра Полос",
- "filters.css_filter_template.desc": "Встроить другой шаблон обработки полос",
- "filters.frame_interpolation": "Интерполяция кадров",
- "filters.frame_interpolation.desc": "Сглаживание между кадрами",
- "filters.noise_gate": "Шумоподавление",
- "filters.noise_gate.desc": "Подавление малых изменений цвета ниже порога",
- "filters.palette_quantization": "Квантизация палитры",
- "filters.palette_quantization.desc": "Сокращение цветов до ограниченной палитры",
- "filters.reverse": "Реверс",
- "filters.reverse.desc": "Изменить порядок светодиодов на обратный",
- "postprocessing.description_label": "Описание (необязательно):",
- "postprocessing.description_placeholder": "Опишите этот шаблон...",
- "postprocessing.created": "Шаблон успешно создан",
- "postprocessing.updated": "Шаблон успешно обновлён",
- "postprocessing.deleted": "Шаблон успешно удалён",
- "postprocessing.delete.confirm": "Вы уверены, что хотите удалить этот шаблон фильтра?",
- "postprocessing.error.load": "Не удалось загрузить шаблоны фильтров",
- "postprocessing.error.required": "Пожалуйста, заполните все обязательные поля",
- "postprocessing.error.delete": "Не удалось удалить шаблон фильтра",
- "postprocessing.config.show": "Показать настройки",
- "postprocessing.test.title": "Тест шаблона фильтра",
- "postprocessing.test.source_stream": "Источник:",
- "postprocessing.test.running": "Тестирование шаблона фильтра...",
- "postprocessing.test.error.no_stream": "Пожалуйста, выберите источник",
- "postprocessing.test.error.failed": "Тест шаблона фильтра не удался",
- "css_processing.title": "Шаблоны Обработки Полос",
- "css_processing.add": "Добавить Шаблон Обработки Полос",
- "css_processing.edit": "Редактировать Шаблон Обработки Полос",
- "css_processing.name": "Имя Шаблона:",
- "css_processing.name_placeholder": "Мой Шаблон Обработки Полос",
- "css_processing.description_label": "Описание (необязательно):",
- "css_processing.description_placeholder": "Опишите этот шаблон...",
- "css_processing.created": "Шаблон обработки полос создан",
- "css_processing.updated": "Шаблон обработки полос обновлён",
- "css_processing.deleted": "Шаблон обработки полос удалён",
- "css_processing.delete.confirm": "Вы уверены, что хотите удалить этот шаблон обработки полос?",
- "css_processing.error.required": "Заполните все обязательные поля",
- "css_processing.error.load": "Ошибка загрузки шаблона обработки полос",
- "css_processing.error.delete": "Ошибка удаления шаблона обработки полос",
- "css_processing.error.clone_failed": "Не удалось клонировать шаблон обработки полос",
- "device.button.stream_selector": "Настройки источника",
- "device.stream_settings.title": "Настройки источника",
- "device.stream_selector.label": "Источник:",
- "device.stream_selector.hint": "Выберите источник, определяющий что это устройство захватывает и обрабатывает",
- "device.stream_selector.none": "-- Источник не назначен --",
- "device.stream_selector.saved": "Настройки источника обновлены",
- "device.stream_settings.border_width": "Ширина границы (px):",
- "device.stream_settings.border_width_hint": "Сколько пикселей от края экрана выбирать для цвета LED (1-100)",
- "device.stream_settings.interpolation": "Режим интерполяции:",
- "device.stream_settings.interpolation.average": "Среднее",
- "device.stream_settings.interpolation.median": "Медиана",
- "device.stream_settings.interpolation.dominant": "Доминантный",
- "device.stream_settings.interpolation_hint": "Как вычислять цвет LED из выбранных пикселей",
- "device.stream_settings.smoothing": "Сглаживание:",
- "device.stream_settings.smoothing_hint": "Временное смешивание между кадрами (0=нет, 1=полное). Уменьшает мерцание.",
- "device.tip.stream_selector": "Настройки источника и проекции LED для этого устройства",
- "streams.group.static_image": "Статические",
- "streams.add.static_image": "Добавить статическое изображение (источник)",
- "streams.edit.static_image": "Редактировать статическое изображение (источник)",
- "streams.type.static_image": "Статическое изображение",
- "streams.group.video": "Видео",
- "streams.add.video": "Добавить видеоисточник",
- "streams.edit.video": "Редактировать видеоисточник",
- "picture_source.type.video": "Видео",
- "picture_source.type.video.desc": "Потоковые кадры из видеофайла, URL или YouTube",
- "picture_source.video.url": "URL видео:",
- "picture_source.video.url.hint": "Локальный файл, HTTP URL или YouTube URL",
- "picture_source.video.url.placeholder": "https://example.com/video.mp4",
- "picture_source.video.loop": "Зацикливание:",
- "picture_source.video.speed": "Скорость воспроизведения:",
- "picture_source.video.start_time": "Время начала (с):",
- "picture_source.video.end_time": "Время окончания (с):",
- "picture_source.video.resolution_limit": "Макс. ширина (px):",
- "picture_source.video.resolution_limit.hint": "Уменьшение видео при декодировании для производительности",
- "streams.image_source": "Источник изображения:",
- "streams.image_source.placeholder": "https://example.com/image.jpg или C:\\path\\to\\image.png",
- "streams.image_source.hint": "Введите URL (http/https) или локальный путь к изображению",
- "streams.validate_image.validating": "Проверка...",
- "streams.validate_image.valid": "Изображение доступно",
- "streams.validate_image.invalid": "Изображение недоступно",
- "targets.title": "Цели",
- "targets.description": "Цели связывают источники цветовых полос с устройствами вывода. Каждая цель ссылается на устройство и источник цветовой полосы.",
- "targets.subtab.wled": "LED",
- "targets.subtab.led": "LED",
- "targets.section.devices": "Устройства",
- "targets.section.color_strips": "Источники цветовых полос",
- "targets.section.targets": "Цели",
- "targets.section.specific_settings": "Специальные настройки",
- "targets.section.advanced": "Расширенные",
- "targets.add": "Добавить Цель",
- "targets.edit": "Редактировать Цель",
- "targets.loading": "Загрузка целей...",
- "targets.none": "Цели не настроены",
- "targets.failed": "Не удалось загрузить цели",
- "targets.name": "Имя Цели:",
- "targets.name.placeholder": "Моя Цель",
- "targets.device": "Устройство:",
- "targets.device.hint": "Выберите LED устройство для передачи данных",
- "targets.device.none": "-- Выберите устройство --",
- "targets.color_strip_source": "Источник цветовой полосы:",
- "targets.color_strip_source.hint": "Выберите источник цветовой полосы, который предоставляет цвета LED для этой цели",
- "targets.no_css": "Нет источника",
- "targets.source": "Источник:",
- "targets.source.hint": "Какой источник изображения захватывать и обрабатывать",
- "targets.source.none": "-- Источник не назначен --",
- "targets.metrics.pipeline": "Детали конвейера",
- "targets.fps": "Целевой FPS:",
- "targets.fps.hint": "Целевая частота кадров для захвата и обновления LED (1-90)",
- "targets.fps.rec": "Макс. аппаратный ≈ {fps} fps ({leds} LED)",
- "targets.border_width": "Ширина границы (px):",
- "targets.border_width.hint": "Сколько пикселей от края экрана выбирать для цвета LED (1-100)",
- "targets.interpolation": "Режим интерполяции:",
- "targets.interpolation.hint": "Как вычислять цвет LED из выбранных пикселей",
- "targets.interpolation.average": "Среднее",
- "targets.interpolation.median": "Медиана",
- "targets.interpolation.dominant": "Доминантный",
- "targets.smoothing": "Сглаживание:",
- "targets.smoothing.hint": "Временное смешивание между кадрами (0=нет, 1=полное). Уменьшает мерцание.",
- "targets.keepalive_interval": "Интервал поддержания связи:",
- "targets.keepalive_interval.hint": "Как часто повторно отправлять последний кадр при статичном источнике для удержания устройства в режиме live (0.5-5.0с)",
- "targets.created": "Цель успешно создана",
- "targets.updated": "Цель успешно обновлена",
- "targets.deleted": "Цель успешно удалена",
- "targets.delete.confirm": "Вы уверены, что хотите удалить эту цель?",
- "targets.error.load": "Не удалось загрузить цели",
- "targets.error.required": "Пожалуйста, заполните все обязательные поля",
- "targets.error.name_required": "Введите название цели",
- "targets.error.delete": "Не удалось удалить цель",
- "targets.button.start": "Запустить",
- "targets.button.stop": "Остановить",
- "targets.status.processing": "Обработка",
- "targets.status.idle": "Ожидание",
- "targets.status.error": "Ошибка",
- "targets.metrics.actual_fps": "Факт. FPS",
- "targets.metrics.target_fps": "Целев. FPS",
- "targets.metrics.frames": "Кадры",
- "targets.metrics.errors": "Ошибки",
- "targets.subtab.key_colors": "Ключевые Цвета",
- "targets.section.key_colors": "Цели Ключевых Цветов",
- "kc.add": "Добавить Цель Ключевых Цветов",
- "kc.edit": "Редактировать Цель Ключевых Цветов",
- "kc.name": "Имя Цели:",
- "kc.name.placeholder": "Моя Цель Ключевых Цветов",
- "kc.source": "Источник:",
- "kc.source.hint": "Из какого источника извлекать цвета",
- "kc.source.none": "-- Источник не назначен --",
- "kc.fps": "FPS Извлечения:",
- "kc.fps.hint": "Сколько раз в секунду извлекать цвета (1-60)",
- "kc.interpolation": "Режим Цвета:",
- "kc.interpolation.hint": "Как вычислять ключевой цвет из пикселей в каждом прямоугольнике",
- "kc.interpolation.average": "Среднее",
- "kc.interpolation.median": "Медиана",
- "kc.interpolation.dominant": "Доминантный",
- "kc.interpolation.average.desc": "Среднее всех цветов пикселей",
- "kc.interpolation.median.desc": "Медианное значение по каналам",
- "kc.interpolation.dominant.desc": "Наиболее частый цвет",
- "kc.smoothing": "Сглаживание:",
- "kc.smoothing.hint": "Временное смешивание между извлечениями (0=нет, 1=полное)",
- "kc.pattern_template": "Шаблон Паттерна:",
- "kc.pattern_template.hint": "Выберите шаблон прямоугольников для извлечения цветов",
- "kc.pattern_template.none": "-- Выберите шаблон паттерна --",
- "kc.brightness_vs": "Источник Яркости:",
- "kc.brightness_vs.hint": "Опциональный источник значений, динамически управляющий яркостью каждый кадр (умножается на ручной слайдер яркости)",
- "kc.brightness_vs.none": "Нет (только ручная яркость)",
- "kc.created": "Цель ключевых цветов успешно создана",
- "kc.updated": "Цель ключевых цветов успешно обновлена",
- "kc.deleted": "Цель ключевых цветов успешно удалена",
- "kc.delete.confirm": "Вы уверены, что хотите удалить эту цель ключевых цветов?",
- "kc.error.no_pattern": "Пожалуйста, выберите шаблон паттерна",
- "kc.error.required": "Пожалуйста, заполните все обязательные поля",
- "kc.colors.none": "Цвета пока не извлечены",
- "kc.test": "Тест",
- "kc.test.error": "Ошибка теста",
- "targets.section.pattern_templates": "Шаблоны Паттернов",
- "pattern.add": "Добавить Шаблон Паттерна",
- "pattern.edit": "Редактировать Шаблон Паттерна",
- "pattern.name": "Имя Шаблона:",
- "pattern.name.placeholder": "Мой Шаблон Паттерна",
- "pattern.description_label": "Описание (необязательно):",
- "pattern.description_placeholder": "Опишите этот паттерн...",
- "pattern.rectangles": "Прямоугольники",
- "pattern.rect.name": "Имя",
- "pattern.rect.x": "X",
- "pattern.rect.y": "Y",
- "pattern.rect.width": "Ш",
- "pattern.rect.height": "В",
- "pattern.rect.add": "Добавить Прямоугольник",
- "pattern.rect.remove": "Удалить",
- "pattern.rect.empty": "Прямоугольники не определены. Добавьте хотя бы один.",
- "pattern.created": "Шаблон паттерна успешно создан",
- "pattern.updated": "Шаблон паттерна успешно обновлён",
- "pattern.deleted": "Шаблон паттерна успешно удалён",
- "pattern.delete.confirm": "Вы уверены, что хотите удалить этот шаблон паттерна?",
- "pattern.delete.referenced": "Невозможно удалить: шаблон используется целью",
- "pattern.error.required": "Пожалуйста, заполните все обязательные поля",
- "pattern.visual_editor": "Визуальный Редактор",
- "pattern.capture_bg": "Захватить Фон",
- "pattern.source_for_bg": "Источник для Фона:",
- "pattern.source_for_bg.none": "-- Выберите источник --",
- "pattern.delete_selected": "Удалить Выбранный",
- "pattern.name.hint": "Описательное имя для этой раскладки прямоугольников",
- "pattern.description.hint": "Необязательные заметки о назначении этого паттерна",
- "pattern.visual_editor.hint": "Нажмите кнопки + чтобы добавить прямоугольники. Тяните края для изменения размера, тяните внутри для перемещения.",
- "pattern.rectangles.hint": "Точная настройка позиций и размеров прямоугольников в координатах (0.0 до 1.0)",
- "overlay.toggle": "Переключить наложение на экран",
- "overlay.button.show": "Показать визуализацию наложения",
- "overlay.button.hide": "Скрыть визуализацию наложения",
- "overlay.started": "Визуализация наложения запущена",
- "overlay.stopped": "Визуализация наложения остановлена",
- "overlay.error.start": "Не удалось запустить наложение",
- "overlay.error.stop": "Не удалось остановить наложение",
- "dashboard.title": "Обзор",
- "dashboard.section.targets": "Цели",
- "dashboard.section.running": "Запущенные",
- "dashboard.section.stopped": "Остановленные",
- "dashboard.no_targets": "Нет настроенных целей",
- "dashboard.uptime": "Время работы",
- "dashboard.fps": "FPS",
- "dashboard.errors": "Ошибки",
- "dashboard.device": "Устройство",
- "dashboard.stop_all": "Остановить все",
- "dashboard.failed": "Не удалось загрузить обзор",
- "dashboard.section.automations": "Автоматизации",
- "dashboard.section.scenes": "Пресеты сцен",
- "dashboard.section.sync_clocks": "Синхронные часы",
- "dashboard.targets": "Цели",
- "dashboard.section.performance": "Производительность системы",
- "dashboard.perf.cpu": "ЦП",
- "dashboard.perf.ram": "ОЗУ",
- "dashboard.perf.gpu": "ГП",
- "dashboard.perf.unavailable": "недоступно",
- "dashboard.perf.color": "Цвет графика",
- "dashboard.poll_interval": "Интервал обновления",
- "automations.title": "Автоматизации",
- "automations.empty": "Автоматизации не настроены. Создайте автоматизацию для автоматической активации сцен.",
- "automations.add": "Добавить автоматизацию",
- "automations.edit": "Редактировать автоматизацию",
- "automations.delete.confirm": "Удалить автоматизацию \"{name}\"?",
- "automations.name": "Название:",
- "automations.name.hint": "Описательное имя для автоматизации",
- "automations.name.placeholder": "Моя автоматизация",
- "automations.enabled": "Включена:",
- "automations.enabled.hint": "Отключённые автоматизации не активируются даже при выполнении условий",
- "automations.condition_logic": "Логика условий:",
- "automations.condition_logic.hint": "Как объединяются несколько условий: ЛЮБОЕ (ИЛИ) или ВСЕ (И)",
- "automations.condition_logic.or": "Любое условие (ИЛИ)",
- "automations.condition_logic.and": "Все условия (И)",
- "automations.condition_logic.or.desc": "Срабатывает при любом совпадении",
- "automations.condition_logic.and.desc": "Срабатывает только при всех",
- "automations.conditions": "Условия:",
- "automations.conditions.hint": "Правила, определяющие когда автоматизация активируется",
- "automations.conditions.add": "Добавить условие",
- "automations.conditions.empty": "Нет условий — автоматизация всегда активна когда включена",
- "automations.condition.always": "Всегда",
- "automations.condition.always.desc": "Всегда активно",
- "automations.condition.always.hint": "Автоматизация активируется сразу при включении и остаётся активной.",
- "automations.condition.startup": "Автозапуск",
- "automations.condition.startup.desc": "При запуске сервера",
- "automations.condition.startup.hint": "Активируется при запуске сервера и остаётся активной пока включена.",
- "automations.condition.application": "Приложение",
- "automations.condition.application.desc": "Приложение запущено",
- "automations.condition.application.apps": "Приложения:",
- "automations.condition.application.apps.hint": "Имена процессов, по одному на строку (например firefox.exe)",
- "automations.condition.application.browse": "Обзор",
- "automations.condition.application.search": "Фильтр процессов...",
- "automations.condition.application.no_processes": "Процессы не найдены",
- "automations.condition.application.match_type": "Тип соответствия:",
- "automations.condition.application.match_type.hint": "Как определять наличие приложения",
- "automations.condition.application.match_type.running": "Запущено",
- "automations.condition.application.match_type.running.desc": "Процесс активен",
- "automations.condition.application.match_type.topmost": "На переднем плане",
- "automations.condition.application.match_type.topmost.desc": "Окно в фокусе",
- "automations.condition.application.match_type.topmost_fullscreen": "Передний план + ПЭ",
- "automations.condition.application.match_type.topmost_fullscreen.desc": "В фокусе + полный экран",
- "automations.condition.application.match_type.fullscreen": "Полный экран",
- "automations.condition.application.match_type.fullscreen.desc": "Любое полноэкранное",
- "automations.condition.time_of_day": "Время суток",
- "automations.condition.time_of_day.desc": "Диапазон времени",
- "automations.condition.time_of_day.start_time": "Время начала:",
- "automations.condition.time_of_day.end_time": "Время окончания:",
- "automations.condition.time_of_day.overnight_hint": "Для ночных диапазонов (например 22:00–06:00) укажите время начала позже времени окончания.",
- "automations.condition.system_idle": "Бездействие системы",
- "automations.condition.system_idle.desc": "Бездействие/активность",
- "automations.condition.system_idle.idle_minutes": "Тайм-аут бездействия (минуты):",
- "automations.condition.system_idle.mode": "Режим срабатывания:",
- "automations.condition.system_idle.when_idle": "При бездействии",
- "automations.condition.system_idle.when_active": "При активности",
- "automations.condition.display_state": "Состояние дисплея",
- "automations.condition.display_state.desc": "Монитор вкл/выкл",
- "automations.condition.display_state.state": "Состояние монитора:",
- "automations.condition.display_state.on": "Включён",
- "automations.condition.display_state.off": "Выключен (спящий режим)",
- "automations.condition.mqtt": "MQTT",
- "automations.condition.mqtt.desc": "MQTT сообщение",
- "automations.condition.mqtt.topic": "Топик:",
- "automations.condition.mqtt.payload": "Значение:",
- "automations.condition.mqtt.match_mode": "Режим сравнения:",
- "automations.condition.mqtt.match_mode.exact": "Точное совпадение",
- "automations.condition.mqtt.match_mode.contains": "Содержит",
- "automations.condition.mqtt.match_mode.regex": "Регулярное выражение",
- "automations.condition.mqtt.hint": "Активировать при получении совпадающего значения по MQTT топику",
- "automations.condition.webhook": "Вебхук",
- "automations.condition.webhook.desc": "HTTP вызов",
- "automations.condition.webhook.hint": "Активировать через HTTP-запрос от внешних сервисов (Home Assistant, IFTTT, curl и т.д.)",
- "automations.condition.webhook.url": "URL вебхука:",
- "automations.condition.webhook.copy": "Скопировать",
- "automations.condition.webhook.copied": "Скопировано!",
- "automations.condition.webhook.save_first": "Сначала сохраните автоматизацию для генерации URL вебхука",
- "automations.scene": "Сцена:",
- "automations.scene.hint": "Пресет сцены для активации при выполнении условий",
- "automations.scene.search_placeholder": "Поиск сцен...",
- "automations.scene.none_selected": "Нет (без сцены)",
- "automations.scene.none_available": "Нет доступных сцен",
- "automations.deactivation_mode": "Деактивация:",
- "automations.deactivation_mode.hint": "Что происходит, когда условия перестают выполняться",
- "automations.deactivation_mode.none": "Ничего",
- "automations.deactivation_mode.none.desc": "Оставить текущее состояние",
- "automations.deactivation_mode.revert": "Откатить",
- "automations.deactivation_mode.revert.desc": "Вернуть предыдущее состояние",
- "automations.deactivation_mode.fallback_scene": "Резервная",
- "automations.deactivation_mode.fallback_scene.desc": "Активировать резервную сцену",
- "automations.deactivation_scene": "Резервная сцена:",
- "automations.deactivation_scene.hint": "Сцена для активации при деактивации автоматизации",
- "automations.status.active": "Активна",
- "automations.status.inactive": "Неактивна",
- "automations.status.disabled": "Отключена",
- "automations.action.disable": "Отключить",
- "automations.last_activated": "Последняя активация",
- "automations.logic.and": " И ",
- "automations.logic.or": " ИЛИ ",
- "automations.logic.all": "ВСЕ",
- "automations.logic.any": "ЛЮБОЕ",
- "automations.updated": "Автоматизация обновлена",
- "automations.created": "Автоматизация создана",
- "automations.deleted": "Автоматизация удалена",
- "automations.error.name_required": "Введите название",
- "automations.error.clone_failed": "Не удалось клонировать автоматизацию",
- "scenes.title": "Сцены",
- "scenes.add": "Захватить сцену",
- "scenes.edit": "Редактировать сцену",
- "scenes.name": "Название:",
- "scenes.name.hint": "Описательное имя для этого пресета сцены",
- "scenes.name.placeholder": "Моя сцена",
- "scenes.description": "Описание:",
- "scenes.description.hint": "Необязательное описание назначения этой сцены",
- "scenes.targets": "Цели:",
- "scenes.targets.hint": "Выберите какие цели включить в снимок сцены",
- "scenes.targets.add": "Добавить цель",
- "scenes.targets.search_placeholder": "Поиск целей...",
- "scenes.capture": "Захват",
- "scenes.activate": "Активировать сцену",
- "scenes.recapture": "Перезахватить текущее состояние",
- "scenes.delete": "Удалить сцену",
- "scenes.targets_count": "целей",
- "scenes.captured": "Сцена захвачена",
- "scenes.updated": "Сцена обновлена",
- "scenes.activated": "Сцена активирована",
- "scenes.activated_partial": "Сцена активирована частично",
- "scenes.errors": "ошибок",
- "scenes.recaptured": "Сцена перезахвачена",
- "scenes.deleted": "Сцена удалена",
- "scenes.recapture_confirm": "Перезахватить текущее состояние в \"{name}\"?",
- "scenes.delete_confirm": "Удалить сцену \"{name}\"?",
- "scenes.error.name_required": "Необходимо указать название",
- "scenes.error.save_failed": "Не удалось сохранить сцену",
- "scenes.error.activate_failed": "Не удалось активировать сцену",
- "scenes.error.recapture_failed": "Не удалось перезахватить сцену",
- "scenes.error.delete_failed": "Не удалось удалить сцену",
- "scenes.cloned": "Сцена клонирована",
- "scenes.error.clone_failed": "Не удалось клонировать сцену",
- "time.hours_minutes": "{h}ч {m}м",
- "time.minutes_seconds": "{m}м {s}с",
- "time.seconds": "{s}с",
- "dashboard.type.led": "LED",
- "dashboard.type.kc": "Цвета клавиш",
- "aria.close": "Закрыть",
- "aria.save": "Сохранить",
- "aria.cancel": "Отмена",
- "aria.previous": "Назад",
- "aria.next": "Вперёд",
- "aria.hint": "Показать подсказку",
- "color_strip.select_type": "Выберите тип цветовой полосы",
- "color_strip.add": "Добавить источник цветовой полосы",
- "color_strip.edit": "Редактировать источник цветовой полосы",
- "color_strip.name": "Название:",
- "color_strip.name.placeholder": "Настенная полоса",
- "color_strip.picture_source": "Источник изображения:",
- "color_strip.picture_source.hint": "Источник захвата экрана для расчёта цветов светодиодов",
- "color_strip.fps": "Целевой FPS:",
- "color_strip.fps.hint": "Целевая частота кадров для обновления цветов светодиодов (10-90)",
- "color_strip.interpolation": "Режим цвета:",
- "color_strip.interpolation.hint": "Как вычислять цвет светодиода по пикселям рамки",
- "color_strip.interpolation.average": "Среднее",
- "color_strip.interpolation.median": "Медиана",
- "color_strip.interpolation.dominant": "Доминирующий",
- "color_strip.interpolation.average.desc": "Смешивает все пиксели в усреднённый цвет",
- "color_strip.interpolation.median.desc": "Берёт средний цвет, игнорируя выбросы",
- "color_strip.interpolation.dominant.desc": "Использует самый частый цвет в выборке",
- "color_strip.smoothing": "Сглаживание:",
- "color_strip.smoothing.hint": "Временное смешивание кадров (0=без смешивания, 1=полное). Уменьшает мерцание.",
- "color_strip.frame_interpolation": "Интерполяция кадров:",
- "color_strip.frame_interpolation.hint": "Смешивает последовательные захваченные кадры для вывода на полной целевой частоте кадров, даже если скорость захвата ниже. Уменьшает заметные ступеньки при плавных переходах.",
- "color_strip.color_corrections": "Цветокоррекция",
- "color_strip.brightness": "Яркость:",
- "color_strip.brightness.hint": "Множитель яркости (0=выкл, 1=без изменений, 2=двойная). Применяется после извлечения цвета.",
- "color_strip.saturation": "Насыщенность:",
- "color_strip.saturation.hint": "Насыщенность цвета (0=оттенки серого, 1=без изменений, 2=двойная насыщенность)",
- "color_strip.gamma": "Гамма:",
- "color_strip.gamma.hint": "Гамма-коррекция (1=без коррекции, <1=ярче средние тона, >1=темнее средние тона)",
- "color_strip.test_device": "Тестировать на устройстве:",
- "color_strip.test_device.hint": "Выберите устройство для отправки тестовых пикселей при нажатии на рамку",
- "color_strip.leds": "Количество светодиодов",
- "color_strip.led_count": "Количество LED:",
- "color_strip.led_count.hint": "Общее число светодиодов на физической полосе. Для источников экрана: 0 = автоматически из калибровки (светодиоды за ТВ будут чёрными). Для статического цвета: укажите точное количество светодиодов устройства.",
- "color_strip.created": "Источник цветовой полосы создан",
- "color_strip.updated": "Источник цветовой полосы обновлён",
- "color_strip.deleted": "Источник цветовой полосы удалён",
- "color_strip.delete.confirm": "Удалить этот источник цветовой полосы?",
- "color_strip.delete.referenced": "Невозможно удалить: источник используется в цели",
- "color_strip.error.name_required": "Введите название",
- "color_strip.type": "Тип:",
- "color_strip.type.hint": "Источник изображения получает цвета светодиодов из захвата экрана. Статический цвет заполняет все светодиоды одним постоянным цветом. Градиент распределяет цветовой градиент по всем светодиодам. Смена цвета плавно циклически переключается между заданными цветами. Композит накладывает несколько источников как смешанные слои. Аудиореактив управляет LED от аудиосигнала в реальном времени. API-ввод принимает массивы цветов LED от внешних клиентов через REST или WebSocket.",
- "color_strip.type.picture": "Источник изображения",
- "color_strip.type.picture.desc": "Цвета из захвата экрана",
- "color_strip.type.picture_advanced": "Мультимонитор",
- "color_strip.type.picture_advanced.desc": "Калибровка линиями по нескольким мониторам",
- "color_strip.type.static": "Статический цвет",
- "color_strip.type.static.desc": "Заливка одним цветом",
- "color_strip.type.gradient": "Градиент",
- "color_strip.type.gradient.desc": "Плавный переход цветов по ленте",
- "color_strip.type.color_cycle": "Смена цвета",
- "color_strip.type.color_cycle.desc": "Циклическая смена списка цветов",
- "color_strip.static_color": "Цвет:",
- "color_strip.static_color.hint": "Статический цвет, который будет отправлен на все светодиоды полосы.",
- "color_strip.gradient.preview": "Градиент:",
- "color_strip.gradient.preview.hint": "Предпросмотр градиента. Нажмите на дорожку маркеров чтобы добавить остановку. Перетащите маркеры для изменения позиции.",
- "color_strip.gradient.stops": "Цветовые остановки:",
- "color_strip.gradient.stops.hint": "Каждая остановка задаёт цвет в относительной позиции (0.0 = начало, 1.0 = конец). Кнопка ↔ добавляет цвет справа для создания резкого перехода.",
- "color_strip.gradient.stops_count": "остановок",
- "color_strip.gradient.add_stop": "+ Добавить",
- "color_strip.gradient.position": "Позиция (0.0–1.0)",
- "color_strip.gradient.bidir.hint": "Добавить второй цвет справа от этой остановки для создания резкого перехода в градиенте.",
- "color_strip.gradient.min_stops": "Градиент должен содержать не менее 2 остановок",
- "color_strip.gradient.preset": "Пресет:",
- "color_strip.gradient.preset.hint": "Загрузить готовую палитру градиента. Выбор пресета заменяет текущие остановки.",
- "color_strip.gradient.preset.custom": "— Свой —",
- "color_strip.gradient.preset.rainbow": "Радуга",
- "color_strip.gradient.preset.sunset": "Закат",
- "color_strip.gradient.preset.ocean": "Океан",
- "color_strip.gradient.preset.forest": "Лес",
- "color_strip.gradient.preset.fire": "Огонь",
- "color_strip.gradient.preset.lava": "Лава",
- "color_strip.gradient.preset.aurora": "Аврора",
- "color_strip.gradient.preset.ice": "Лёд",
- "color_strip.gradient.preset.warm": "Тёплый",
- "color_strip.gradient.preset.cool": "Холодный",
- "color_strip.gradient.preset.neon": "Неон",
- "color_strip.gradient.preset.pastel": "Пастельный",
- "color_strip.gradient.preset.save_button": "Сохранить как пресет…",
- "color_strip.gradient.preset.save_prompt": "Введите название пресета:",
- "color_strip.gradient.preset.saved": "Пресет сохранён",
- "color_strip.gradient.preset.deleted": "Пресет удалён",
- "color_strip.gradient.preset.apply": "Применить",
- "color_strip.animation": "Анимация",
- "color_strip.animation.type": "Эффект:",
- "color_strip.animation.type.hint": "Эффект анимации.",
- "color_strip.animation.type.none": "Нет (без эффекта анимации)",
- "color_strip.animation.type.none.desc": "Статичные цвета без анимации",
- "color_strip.animation.type.breathing": "Дыхание",
- "color_strip.animation.type.breathing.desc": "Плавное угасание и нарастание яркости",
- "color_strip.animation.type.color_cycle": "Смена цвета",
- "color_strip.animation.type.gradient_shift": "Сдвиг градиента",
- "color_strip.animation.type.gradient_shift.desc": "Сдвигает градиент вдоль ленты",
- "color_strip.animation.type.wave": "Волна",
- "color_strip.animation.type.wave.desc": "Синусоидальная волна яркости вдоль ленты",
- "color_strip.animation.type.strobe": "Стробоскоп",
- "color_strip.animation.type.strobe.desc": "Быстрое мигание вкл/выкл",
- "color_strip.animation.type.sparkle": "Искры",
- "color_strip.animation.type.sparkle.desc": "Случайные светодиоды кратковременно вспыхивают",
- "color_strip.animation.type.pulse": "Пульс",
- "color_strip.animation.type.pulse.desc": "Резкая вспышка яркости с быстрым затуханием",
- "color_strip.animation.type.candle": "Свеча",
- "color_strip.animation.type.candle.desc": "Тёплое мерцание, как у свечи",
- "color_strip.animation.type.rainbow_fade": "Радужный перелив",
- "color_strip.animation.type.rainbow_fade.desc": "Циклический переход по всему спектру оттенков",
- "color_strip.animation.speed": "Скорость:",
- "color_strip.animation.speed.hint": "Множитель скорости анимации. 1.0 ≈ один цикл в секунду для дыхания; большие значения ускоряют анимацию.",
- "color_strip.color_cycle.colors": "Цвета:",
- "color_strip.color_cycle.colors.hint": "Список цветов для плавной циклической смены. Минимум 2 цвета. По умолчанию — полный радужный спектр.",
- "color_strip.color_cycle.add_color": "+ Добавить цвет",
- "color_strip.color_cycle.speed": "Скорость:",
- "color_strip.color_cycle.speed.hint": "Множитель скорости смены. 1.0 ≈ один полный цикл за 20 секунд; большие значения ускоряют смену.",
- "color_strip.color_cycle.min_colors": "Смена цвета должна содержать не менее 2 цветов",
- "color_strip.type.effect": "Эффект",
- "color_strip.type.effect.desc": "Процедурные эффекты: огонь, плазма, аврора",
- "color_strip.type.effect.hint": "Процедурные LED-эффекты (огонь, метеор, плазма, шум, аврора), генерируемые в реальном времени.",
- "color_strip.type.composite": "Композит",
- "color_strip.type.composite.desc": "Наложение и смешивание источников",
- "color_strip.type.composite.hint": "Наложение нескольких источников цветовой ленты как слоёв с режимами смешивания и прозрачностью.",
- "color_strip.type.mapped": "Маппинг",
- "color_strip.type.mapped.desc": "Назначение источников на зоны LED",
- "color_strip.type.mapped.hint": "Назначает разные источники цветовой полосы на разные диапазоны LED (зоны). В отличие от композита, маппинг размещает источники рядом друг с другом.",
- "color_strip.type.audio": "Аудиореактив",
- "color_strip.type.audio.desc": "LED от аудиосигнала",
- "color_strip.type.audio.hint": "Цвета LED управляются аудиосигналом в реальном времени — системный звук или микрофон.",
- "color_strip.type.api_input": "API-ввод",
- "color_strip.type.api_input.desc": "Приём цветов от внешних приложений",
- "color_strip.type.api_input.hint": "Принимает массивы цветов LED от внешних клиентов через REST POST или WebSocket. Используйте для интеграции с собственным ПО, домашней автоматизацией или любой системой, способной отправлять HTTP-запросы.",
- "color_strip.api_input.fallback_color": "Цвет по умолчанию:",
- "color_strip.api_input.fallback_color.hint": "Цвет для отображения, когда данные не получены в течение периода ожидания. LED покажут этот цвет при запуске и после потери соединения.",
- "color_strip.api_input.timeout": "Тайм-аут (секунды):",
- "color_strip.api_input.timeout.hint": "Время ожидания новых данных о цветах перед возвратом к цвету по умолчанию. Установите 0, чтобы не использовать тайм-аут.",
- "color_strip.api_input.endpoints": "Эндпоинты для отправки:",
- "color_strip.api_input.endpoints.hint": "Используйте эти URL для отправки данных о цветах LED из вашего внешнего приложения. REST принимает JSON, WebSocket принимает как JSON, так и бинарные кадры.",
- "color_strip.api_input.save_first": "Сначала сохраните источник, чтобы увидеть URL эндпоинтов.",
- "color_strip.type.notification": "Уведомления",
- "color_strip.type.notification.desc": "Разовый эффект по вебхуку",
- "color_strip.type.notification.hint": "Вспышка, пульс или волна при срабатывании через вебхук. Предназначен для использования как слой в композитном источнике.",
- "color_strip.notification.effect": "Эффект:",
- "color_strip.notification.effect.hint": "Визуальный эффект при уведомлении. Вспышка — линейное затухание, Пульс — плавная волна, Волна — заполнение и затухание.",
- "color_strip.notification.effect.flash": "Вспышка",
- "color_strip.notification.effect.flash.desc": "Мгновенное включение, линейное затухание",
- "color_strip.notification.effect.pulse": "Пульс",
- "color_strip.notification.effect.pulse.desc": "Плавное свечение колоколом",
- "color_strip.notification.effect.sweep": "Волна",
- "color_strip.notification.effect.sweep.desc": "Заполняет слева направо, затем гаснет",
- "color_strip.notification.duration": "Длительность (мс):",
- "color_strip.notification.duration.hint": "Как долго длится эффект уведомления в миллисекундах.",
- "color_strip.notification.default_color": "Цвет по умолчанию:",
- "color_strip.notification.default_color.hint": "Цвет, когда для приложения нет специфического назначения цвета.",
- "color_strip.notification.filter_mode": "Фильтр приложений:",
- "color_strip.notification.filter_mode.hint": "Фильтр уведомлений по имени приложения. Выкл = все, Белый список = только указанные, Чёрный список = все кроме указанных.",
- "color_strip.notification.filter_mode.off": "Выкл",
- "color_strip.notification.filter_mode.whitelist": "Белый список",
- "color_strip.notification.filter_mode.blacklist": "Чёрный список",
- "color_strip.notification.filter_mode.off.desc": "Принимать все уведомления",
- "color_strip.notification.filter_mode.whitelist.desc": "Только указанные приложения",
- "color_strip.notification.filter_mode.blacklist.desc": "Все кроме указанных приложений",
- "color_strip.notification.filter_list": "Список приложений:",
- "color_strip.notification.filter_list.hint": "Одно имя приложения на строку. Используйте «Обзор» для выбора из запущенных процессов.",
- "color_strip.notification.filter_list.placeholder": "Discord\nSlack\nTelegram",
- "color_strip.notification.app_colors": "Цвета приложений",
- "color_strip.notification.app_colors.label": "Назначения цветов:",
- "color_strip.notification.app_colors.hint": "Индивидуальные цвета для приложений. Каждая строка связывает имя приложения с цветом уведомления.",
- "color_strip.notification.app_colors.add": "+ Добавить",
- "color_strip.notification.endpoint": "Вебхук:",
- "color_strip.notification.endpoint.hint": "URL для запуска уведомлений из внешних систем. POST с JSON телом: {\"app\": \"AppName\", \"color\": \"#FF0000\"}.",
- "color_strip.notification.save_first": "Сначала сохраните источник, чтобы увидеть URL вебхука.",
- "color_strip.notification.app_count": "прилож.",
- "color_strip.notification.test": "Тестовое уведомление",
- "color_strip.notification.test.ok": "Уведомление отправлено",
- "color_strip.notification.test.no_streams": "Нет запущенных потоков для этого источника",
- "color_strip.notification.test.error": "Не удалось отправить уведомление",
- "color_strip.notification.history.title": "История уведомлений",
- "color_strip.notification.history.hint": "Последние ОС-уведомления, захваченные слушателем (новейшие сверху). До 50 записей.",
- "color_strip.notification.history.empty": "Уведомления ещё не захвачены",
- "color_strip.notification.history.unavailable": "Слушатель уведомлений ОС недоступен на этой платформе",
- "color_strip.notification.history.error": "Не удалось загрузить историю уведомлений",
- "color_strip.notification.history.refresh": "Обновить",
- "color_strip.notification.history.unknown_app": "Неизвестное приложение",
- "color_strip.notification.history.fired": "Потоков запущено",
- "color_strip.notification.history.filtered": "Потоков отфильтровано",
- "color_strip.test.title": "Предпросмотр",
- "color_strip.test.connecting": "Подключение...",
- "color_strip.test.error": "Не удалось подключиться к потоку предпросмотра",
- "color_strip.test.led_count": "Кол-во LED:",
- "color_strip.test.fps": "FPS:",
- "color_strip.test.receive_fps": "Частота приёма",
- "color_strip.test.apply": "Применить",
- "color_strip.test.composite": "Композит",
- "color_strip.preview.title": "Предпросмотр",
- "color_strip.preview.not_connected": "Не подключено",
- "color_strip.preview.connecting": "Подключение...",
- "color_strip.preview.connected": "Подключено",
- "color_strip.preview.unsupported": "Предпросмотр недоступен для этого типа источника",
- "color_strip.type.daylight": "Дневной цикл",
- "color_strip.type.daylight.desc": "Имитация естественного дневного света за 24 часа",
- "color_strip.type.daylight.hint": "Имитирует цветовую температуру солнца в течение суток — от тёплого рассвета до прохладного дневного света, заката и ночи.",
- "color_strip.daylight.speed": "Скорость:",
- "color_strip.daylight.speed.hint": "Множитель скорости цикла. 1.0 = полный цикл день/ночь за ~4 минуты.",
- "color_strip.daylight.use_real_time": "Реальное время:",
- "color_strip.daylight.use_real_time.hint": "Если включено, цвет LED соответствует реальному времени суток. Настройка скорости игнорируется.",
- "color_strip.daylight.real_time": "Реальное время",
- "color_strip.daylight.latitude": "Широта:",
- "color_strip.daylight.latitude.hint": "Географическая широта (-90 до 90). Влияет на время восхода/заката в режиме реального времени.",
- "color_strip.type.candlelight": "Свечи",
- "color_strip.type.candlelight.desc": "Реалистичная имитация мерцания свечей",
- "color_strip.type.candlelight.hint": "Реалистичное мерцание свечей с тёплыми тонами и органическими паттернами.",
- "color_strip.candlelight.color": "Базовый цвет:",
- "color_strip.candlelight.color.hint": "Тёплый базовый цвет пламени свечи. По умолчанию — натуральный тёплый янтарь.",
- "color_strip.candlelight.intensity": "Интенсивность мерцания:",
- "color_strip.candlelight.intensity.hint": "Сила мерцания свечей. Низкие значения — мягкое свечение, высокие — свеча на ветру.",
- "color_strip.candlelight.num_candles_label": "Количество свечей:",
- "color_strip.candlelight.num_candles": "свечей",
- "color_strip.candlelight.num_candles.hint": "Сколько независимых источников свечей вдоль ленты. Каждый мерцает по-своему.",
- "color_strip.candlelight.speed": "Скорость мерцания:",
- "color_strip.candlelight.speed.hint": "Скорость анимации мерцания. Большие значения — более быстрое, беспокойное пламя.",
- "color_strip.type.processed": "Обработанный",
- "color_strip.type.processed.desc": "Применить шаблон обработки к другому источнику",
- "color_strip.type.processed.hint": "Оборачивает существующий источник цветовой полосы и пропускает его вывод через цепочку фильтров.",
- "color_strip.processed.input": "Источник:",
- "color_strip.processed.input.hint": "Источник цветовой полосы, вывод которого будет обработан",
- "color_strip.processed.template": "Шаблон обработки:",
- "color_strip.processed.template.hint": "Цепочка фильтров для применения к выводу входного источника",
- "color_strip.processed.error.no_input": "Выберите входной источник",
- "color_strip.composite.layers": "Слои:",
- "color_strip.composite.layers.hint": "Наложение нескольких источников. Первый слой — нижний, последний — верхний. Каждый слой может иметь свой режим смешивания и прозрачность.",
- "color_strip.composite.add_layer": "+ Добавить слой",
- "color_strip.composite.source": "Источник",
- "color_strip.composite.blend_mode": "Смешивание",
- "color_strip.composite.blend_mode.normal": "Обычное",
- "color_strip.composite.blend_mode.normal.desc": "Стандартное альфа-смешивание",
- "color_strip.composite.blend_mode.add": "Сложение",
- "color_strip.composite.blend_mode.add.desc": "Осветляет, складывая цвета",
- "color_strip.composite.blend_mode.multiply": "Умножение",
- "color_strip.composite.blend_mode.multiply.desc": "Затемняет, умножая цвета",
- "color_strip.composite.blend_mode.screen": "Экран",
- "color_strip.composite.blend_mode.screen.desc": "Осветляет, обратное умножение",
- "color_strip.composite.blend_mode.override": "Замена",
- "color_strip.composite.blend_mode.override.desc": "Чёрный = прозрачный, яркий = непрозрачный",
- "color_strip.composite.opacity": "Непрозрачность",
- "color_strip.composite.brightness": "Яркость",
- "color_strip.composite.brightness.none": "Нет (полная яркость)",
- "color_strip.composite.processing": "Обработка",
- "color_strip.composite.enabled": "Включён",
- "color_strip.composite.error.min_layers": "Необходим хотя бы 1 слой",
- "color_strip.composite.error.no_source": "Для каждого слоя должен быть выбран источник",
- "color_strip.composite.layers_count": "слоёв",
- "color_strip.mapped.zones": "Зоны:",
- "color_strip.mapped.zones.hint": "Каждая зона привязывает источник цветовой полосы к определённому диапазону LED. Зоны размещаются рядом — промежутки остаются чёрными.",
- "color_strip.mapped.add_zone": "+ Добавить зону",
- "color_strip.mapped.zone_source": "Источник",
- "color_strip.mapped.zone_start": "Начало LED",
- "color_strip.mapped.zone_end": "Конец LED",
- "color_strip.mapped.zone_reverse": "Реверс",
- "color_strip.mapped.zones_count": "зон",
- "color_strip.mapped.select_source": "Поиск источников...",
- "color_strip.mapped.error.no_source": "Для каждой зоны должен быть выбран источник",
- "color_strip.audio.visualization": "Визуализация:",
- "color_strip.audio.visualization.hint": "Способ отображения аудиоданных на LED.",
- "color_strip.audio.viz.spectrum": "Анализатор спектра",
- "color_strip.audio.viz.spectrum.desc": "Частотные полосы по ленте",
- "color_strip.audio.viz.beat_pulse": "Пульс бита",
- "color_strip.audio.viz.beat_pulse.desc": "Все LED пульсируют в такт",
- "color_strip.audio.viz.vu_meter": "VU-метр",
- "color_strip.audio.viz.vu_meter.desc": "Уровень громкости заполняет ленту",
- "color_strip.audio.source": "Аудиоисточник:",
- "color_strip.audio.source.hint": "Аудиоисточник для визуализации. Может быть многоканальным (устройство) или моно (один канал). Создавайте и управляйте аудиоисточниками на вкладке Источники.",
- "color_strip.audio.sensitivity": "Чувствительность:",
- "color_strip.audio.sensitivity.hint": "Множитель усиления аудиосигнала. Более высокие значения делают LED чувствительнее к тихим звукам.",
- "color_strip.audio.smoothing": "Сглаживание:",
- "color_strip.audio.smoothing.hint": "Временное сглаживание между кадрами. Более высокие значения дают плавную, но медленнее реагирующую визуализацию.",
- "color_strip.audio.palette": "Палитра:",
- "color_strip.audio.palette.hint": "Цветовая палитра для полос спектра или пульсации бита.",
- "color_strip.audio.color": "Базовый цвет:",
- "color_strip.audio.color.hint": "Цвет низкого уровня для полосы VU-метра.",
- "color_strip.audio.color_peak": "Пиковый цвет:",
- "color_strip.audio.color_peak.hint": "Цвет высокого уровня в верхней части полосы VU-метра.",
- "color_strip.audio.mirror": "Зеркало:",
- "color_strip.audio.mirror.hint": "Зеркалирование спектра от центра к краям: басы в середине, высокие частоты по краям.",
- "color_strip.effect.type": "Тип эффекта:",
- "color_strip.effect.type.hint": "Выберите процедурный алгоритм.",
- "color_strip.effect.fire": "Огонь",
- "color_strip.effect.fire.desc": "Клеточный автомат, имитирующий поднимающееся пламя с диффузией тепла",
- "color_strip.effect.meteor": "Метеор",
- "color_strip.effect.meteor.desc": "Яркая точка движется по ленте с экспоненциально затухающим хвостом",
- "color_strip.effect.plasma": "Плазма",
- "color_strip.effect.plasma.desc": "Наложение синусоидальных волн с палитрой — классический демо-эффект",
- "color_strip.effect.noise": "Шум",
- "color_strip.effect.noise.desc": "Прокручиваемый фрактальный шум, отображённый на палитру",
- "color_strip.effect.aurora": "Аврора",
- "color_strip.effect.aurora.desc": "Наложенные шумовые полосы, дрейфующие и смешивающиеся — в стиле северного сияния",
- "color_strip.effect.speed": "Скорость:",
- "color_strip.effect.speed.hint": "Множитель скорости анимации эффекта (0.1 = очень медленно, 10.0 = очень быстро).",
- "color_strip.effect.palette": "Палитра:",
- "color_strip.effect.palette.hint": "Цветовая палитра для отображения значений эффекта в RGB-цвета.",
- "color_strip.effect.color": "Цвет метеора:",
- "color_strip.effect.color.hint": "Цвет головной точки метеора.",
- "color_strip.effect.intensity": "Интенсивность:",
- "color_strip.effect.intensity.hint": "Интенсивность эффекта — частота искр (огонь), затухание хвоста (метеор) или диапазон яркости (аврора).",
- "color_strip.effect.scale": "Масштаб:",
- "color_strip.effect.scale.hint": "Пространственный масштаб — частота волн (плазма), уровень масштабирования (шум) или ширина полос (аврора).",
- "color_strip.effect.mirror": "Отражение:",
- "color_strip.effect.mirror.hint": "Режим отскока — метеор меняет направление у краёв ленты вместо переноса.",
- "color_strip.palette.fire": "Огонь",
- "color_strip.palette.ocean": "Океан",
- "color_strip.palette.lava": "Лава",
- "color_strip.palette.forest": "Лес",
- "color_strip.palette.rainbow": "Радуга",
- "color_strip.palette.aurora": "Аврора",
- "color_strip.palette.sunset": "Закат",
- "color_strip.palette.ice": "Лёд",
- "audio_source.title": "Аудиоисточники",
- "audio_source.group.multichannel": "Многоканальные",
- "audio_source.group.mono": "Моно",
- "audio_source.add": "Добавить аудиоисточник",
- "audio_source.add.multichannel": "Добавить многоканальный",
- "audio_source.add.mono": "Добавить моно",
- "audio_source.edit": "Редактировать аудиоисточник",
- "audio_source.edit.multichannel": "Редактировать многоканальный",
- "audio_source.edit.mono": "Редактировать моно",
- "audio_source.name": "Название:",
- "audio_source.name.placeholder": "Системный звук",
- "audio_source.name.hint": "Описательное имя для этого аудиоисточника",
- "audio_source.type": "Тип:",
- "audio_source.type.hint": "Многоканальный захватывает все каналы с аудиоустройства. Моно извлекает один канал из многоканального источника.",
- "audio_source.type.multichannel": "Многоканальный",
- "audio_source.type.mono": "Моно",
- "audio_source.device": "Аудиоустройство:",
- "audio_source.device.hint": "Источник аудиосигнала. Устройства обратной петли захватывают системный звук; устройства ввода — микрофон или линейный вход.",
- "audio_source.refresh_devices": "Обновить устройства",
- "audio_source.parent": "Родительский источник:",
- "audio_source.parent.hint": "Многоканальный источник для извлечения канала",
- "audio_source.channel": "Канал:",
- "audio_source.channel.hint": "Какой аудиоканал извлечь из многоканального источника",
- "audio_source.channel.mono": "Моно (Л+П микс)",
- "audio_source.channel.left": "Левый",
- "audio_source.channel.right": "Правый",
- "audio_source.description": "Описание (необязательно):",
- "audio_source.description.placeholder": "Опишите этот аудиоисточник...",
- "audio_source.description.hint": "Необязательные заметки об этом аудиоисточнике",
- "audio_source.created": "Аудиоисточник создан",
- "audio_source.updated": "Аудиоисточник обновлён",
- "audio_source.deleted": "Аудиоисточник удалён",
- "audio_source.delete.confirm": "Удалить этот аудиоисточник?",
- "audio_source.error.name_required": "Введите название",
- "audio_source.audio_template": "Аудиошаблон:",
- "audio_source.audio_template.hint": "Шаблон аудиозахвата определяет, какой движок и настройки использовать для этого устройства",
- "audio_source.test": "Тест",
- "audio_source.test.title": "Тест аудиоисточника",
- "audio_source.test.rms": "RMS",
- "audio_source.test.peak": "Пик",
- "audio_source.test.beat": "Бит",
- "audio_source.test.connecting": "Подключение...",
- "audio_source.test.error": "Ошибка теста аудио",
- "audio_template.test": "Тест",
- "audio_template.test.title": "Тест аудиошаблона",
- "audio_template.test.device": "Аудиоустройство:",
- "audio_template.test.device.hint": "Выберите устройство для захвата звука во время теста",
- "audio_template.test.run": "Запуск",
- "audio_template.title": "Аудиошаблоны",
- "audio_template.add": "Добавить аудиошаблон",
- "audio_template.edit": "Редактировать аудиошаблон",
- "audio_template.name": "Название шаблона:",
- "audio_template.name.placeholder": "Мой аудиошаблон",
- "audio_template.description.label": "Описание (необязательно):",
- "audio_template.description.placeholder": "Опишите этот шаблон...",
- "audio_template.engine": "Аудиодвижок:",
- "audio_template.engine.hint": "Выберите движок аудиозахвата. WASAPI — только Windows с поддержкой loopback. Sounddevice — кроссплатформенный.",
- "audio_template.engine.unavailable": "Недоступен",
- "audio_template.engine.unavailable.hint": "Этот движок недоступен в вашей системе",
- "audio_template.config": "Конфигурация",
- "audio_template.config.show": "Показать конфигурацию",
- "audio_template.created": "Аудиошаблон создан",
- "audio_template.updated": "Аудиошаблон обновлён",
- "audio_template.deleted": "Аудиошаблон удалён",
- "audio_template.delete.confirm": "Удалить этот аудиошаблон?",
- "audio_template.error.load": "Не удалось загрузить аудиошаблоны",
- "audio_template.error.engines": "Не удалось загрузить аудиодвижки",
- "audio_template.error.required": "Пожалуйста, заполните все обязательные поля",
- "audio_template.error.delete": "Не удалось удалить аудиошаблон",
- "streams.group.value": "Источники значений",
- "streams.group.sync": "Часы синхронизации",
- "tree.group.picture": "Источники изображений",
- "tree.group.capture": "Захват экрана",
- "tree.group.static": "Статичные",
- "tree.group.processing": "Обработанные",
- "tree.group.strip": "Цветовые полосы",
- "tree.group.audio": "Аудио",
- "tree.group.utility": "Утилиты",
- "tree.leaf.sources": "Источники",
- "tree.leaf.engine_templates": "Шаблоны движка",
- "tree.leaf.images": "Изображения",
- "tree.leaf.video": "Видео",
- "tree.leaf.filter_templates": "Шаблоны фильтров",
- "tree.leaf.processing_templates": "Шаблоны обработки",
- "tree.leaf.templates": "Шаблоны",
- "value_source.group.title": "Источники значений",
- "value_source.select_type": "Выберите тип источника значений",
- "value_source.add": "Добавить источник значений",
- "value_source.edit": "Редактировать источник значений",
- "value_source.name": "Название:",
- "value_source.name.placeholder": "Пульс яркости",
- "value_source.name.hint": "Описательное имя для этого источника значений",
- "value_source.type": "Тип:",
- "value_source.type.hint": "Статический выдаёт постоянное значение. Анимированный циклически меняет форму волны. Аудио реагирует на звук. Адаптивные типы автоматически подстраивают яркость по времени суток или содержимому сцены.",
- "value_source.type.static": "Статический",
- "value_source.type.static.desc": "Постоянное выходное значение",
- "value_source.type.animated": "Анимированный",
- "value_source.type.animated.desc": "Циклическая смена по форме волны",
- "value_source.type.audio": "Аудио",
- "value_source.type.audio.desc": "Реагирует на звуковой сигнал",
- "value_source.type.adaptive_time": "Адаптивный (Время)",
- "value_source.type.adaptive_time.desc": "Подстройка по времени суток",
- "value_source.type.adaptive_scene": "Адаптивный (Сцена)",
- "value_source.type.adaptive_scene.desc": "Подстройка по содержимому сцены",
- "value_source.type.daylight": "Дневной цикл",
- "value_source.type.daylight.desc": "Яркость следует за циклом дня/ночи",
- "value_source.daylight.speed": "Скорость:",
- "value_source.daylight.speed.hint": "Множитель скорости цикла. 1.0 = полный цикл день/ночь за ~4 минуты.",
- "value_source.daylight.use_real_time": "Реальное время:",
- "value_source.daylight.use_real_time.hint": "Яркость следует за реальным временем суток. Скорость игнорируется.",
- "value_source.daylight.enable_real_time": "Следовать за часами",
- "value_source.daylight.latitude": "Широта:",
- "value_source.daylight.latitude.hint": "Географическая широта (-90 до 90). Влияет на время восхода/заката в режиме реального времени.",
- "value_source.daylight.real_time": "Реальное время",
- "value_source.daylight.speed_label": "Скорость",
- "value_source.value": "Значение:",
- "value_source.value.hint": "Постоянное выходное значение (0.0 = выкл, 1.0 = полная яркость)",
- "value_source.waveform": "Форма волны:",
- "value_source.waveform.hint": "Форма цикла анимации яркости",
- "value_source.waveform.sine": "Синус",
- "value_source.waveform.triangle": "Треугольник",
- "value_source.waveform.square": "Прямоугольник",
- "value_source.waveform.sawtooth": "Пила",
- "value_source.speed": "Скорость (цикл/мин):",
- "value_source.speed.hint": "Циклов в минуту — как быстро повторяется волна (1 = очень медленно, 120 = очень быстро)",
- "value_source.min_value": "Мин. значение:",
- "value_source.min_value.hint": "Минимальный выход цикла волны",
- "value_source.max_value": "Макс. значение:",
- "value_source.max_value.hint": "Максимальный выход цикла волны",
- "value_source.audio_source": "Аудиоисточник:",
- "value_source.audio_source.hint": "Аудиоисточник для считывания уровня звука (многоканальный или моно)",
- "value_source.mode": "Режим:",
- "value_source.mode.hint": "RMS измеряет среднюю громкость. Пик отслеживает самые громкие моменты. Бит реагирует на ритм.",
- "value_source.mode.rms": "RMS (Громкость)",
- "value_source.mode.peak": "Пик",
- "value_source.mode.beat": "Бит",
- "value_source.mode.rms.desc": "Средний уровень громкости",
- "value_source.mode.peak.desc": "Отслеживание пиковых моментов",
- "value_source.mode.beat.desc": "Детекция ритмических ударов",
- "value_source.auto_gain": "Авто-усиление:",
- "value_source.auto_gain.hint": "Автоматически нормализует уровни звука, чтобы выходное значение использовало полный диапазон независимо от громкости входного сигнала",
- "value_source.auto_gain.enable": "Включить авто-усиление",
- "value_source.sensitivity": "Чувствительность:",
- "value_source.sensitivity.hint": "Множитель усиления аудиосигнала (выше = более реактивный)",
- "value_source.scene_sensitivity.hint": "Множитель усиления сигнала яркости (выше = более чувствительный к изменениям яркости)",
- "value_source.smoothing": "Сглаживание:",
- "value_source.smoothing.hint": "Временное сглаживание (0 = мгновенный отклик, 1 = очень плавный/медленный)",
- "value_source.audio_min_value": "Мин. значение:",
- "value_source.audio_min_value.hint": "Выход при тишине (напр. 0.3 = минимум 30% яркости)",
- "value_source.audio_max_value": "Макс. значение:",
- "value_source.audio_max_value.hint": "Выход при максимальном уровне звука",
- "value_source.schedule": "Расписание:",
- "value_source.schedule.hint": "Определите минимум 2 временные точки. Яркость линейно интерполируется между ними, с переходом через полночь.",
- "value_source.schedule.add": "+ Добавить точку",
- "value_source.schedule.points": "точек",
- "value_source.picture_source": "Источник изображения:",
- "value_source.picture_source.hint": "Источник изображения, кадры которого будут анализироваться на среднюю яркость.",
- "value_source.scene_behavior": "Поведение:",
- "value_source.scene_behavior.hint": "Дополнение: тёмная сцена = высокая яркость (для фоновой подсветки). Совпадение: яркая сцена = высокая яркость.",
- "value_source.scene_behavior.complement": "Дополнение (тёмный → ярко)",
- "value_source.scene_behavior.match": "Совпадение (яркий → ярко)",
- "value_source.adaptive_min_value": "Мин. значение:",
- "value_source.adaptive_min_value.hint": "Минимальная выходная яркость",
- "value_source.adaptive_max_value": "Макс. значение:",
- "value_source.adaptive_max_value.hint": "Максимальная выходная яркость",
- "value_source.error.schedule_min": "Расписание требует минимум 2 временные точки",
- "value_source.description": "Описание (необязательно):",
- "value_source.description.placeholder": "Опишите этот источник значений...",
- "value_source.description.hint": "Необязательные заметки об этом источнике значений",
- "value_source.created": "Источник значений создан",
- "value_source.updated": "Источник значений обновлён",
- "value_source.deleted": "Источник значений удалён",
- "value_source.delete.confirm": "Удалить этот источник значений?",
- "value_source.error.name_required": "Введите название",
- "value_source.test": "Тест",
- "value_source.test.title": "Тест источника значений",
- "value_source.test.connecting": "Подключение...",
- "value_source.test.error": "Не удалось подключиться",
- "value_source.test.current": "Текущее",
- "value_source.test.min": "Мин",
- "value_source.test.max": "Макс",
- "test.frames": "Кадры",
- "test.fps": "Кадр/с",
- "test.avg_capture": "Сред",
- "targets.brightness_vs": "Источник яркости:",
- "targets.brightness_vs.hint": "Необязательный источник значений для динамического управления яркостью каждый кадр (переопределяет яркость устройства)",
- "targets.brightness_vs.none": "Нет (яркость устройства)",
- "targets.min_brightness_threshold": "Мин. порог яркости:",
- "targets.min_brightness_threshold.hint": "Если итоговая яркость (яркость пикселей × яркость устройства/источника) ниже этого значения, светодиоды полностью выключаются (0 = отключено)",
- "targets.adaptive_fps": "Адаптивный FPS:",
- "targets.adaptive_fps.hint": "Автоматически снижает частоту отправки, когда устройство перестаёт отвечать, и постепенно восстанавливает её при стабилизации. Рекомендуется для WiFi-устройств со слабым сигналом.",
- "targets.protocol": "Протокол:",
- "targets.protocol.hint": "DDP отправляет пиксели по быстрому UDP (рекомендуется). HTTP использует JSON API — медленнее, но надёжнее, ограничение ~500 LED.",
- "targets.protocol.ddp": "DDP (UDP)",
- "targets.protocol.ddp.desc": "Быстрые UDP-пакеты — рекомендуется",
- "targets.protocol.http": "HTTP",
- "targets.protocol.http.desc": "JSON API — медленнее, ≤500 LED",
- "targets.protocol.serial": "Serial",
- "search.open": "Поиск (Ctrl+K)",
- "search.placeholder": "Поиск... (Ctrl+K)",
- "search.loading": "Загрузка...",
- "search.no_results": "Ничего не найдено",
- "search.group.devices": "Устройства",
- "search.group.targets": "LED-цели",
- "search.group.kc_targets": "Цели Key Colors",
- "search.group.css": "Источники цветных лент",
- "search.group.automations": "Автоматизации",
- "search.group.streams": "Потоки изображений",
- "search.group.capture_templates": "Шаблоны захвата",
- "search.group.pp_templates": "Шаблоны постобработки",
- "search.group.pattern_templates": "Шаблоны паттернов",
- "search.group.audio": "Аудиоисточники",
- "search.group.value": "Источники значений",
- "search.group.scenes": "Пресеты сцен",
- "search.group.cspt": "Шаблоны обработки полос",
- "search.group.sync_clocks": "Синхронные часы",
- "search.group.actions": "Действия",
- "search.action.start": "Запустить",
- "search.action.stop": "Остановить",
- "search.action.activate": "Активировать",
- "search.action.enable": "Включить",
- "search.action.disable": "Отключить",
- "settings.backup.label": "Резервное копирование",
- "settings.backup.hint": "Скачать всю конфигурацию (устройства, цели, потоки, шаблоны, автоматизации) в виде одного JSON-файла.",
- "settings.backup.button": "Скачать резервную копию",
- "settings.backup.success": "Резервная копия скачана",
- "settings.backup.error": "Ошибка скачивания резервной копии",
- "settings.restore.label": "Восстановление конфигурации",
- "settings.restore.hint": "Загрузите ранее сохранённый файл резервной копии для замены всей конфигурации. Сервер перезапустится автоматически.",
- "settings.restore.button": "Восстановить из копии",
- "settings.restore.confirm": "Это заменит ВСЮ конфигурацию и перезапустит сервер. Вы уверены?",
- "settings.restore.success": "Конфигурация восстановлена",
- "settings.restore.error": "Ошибка восстановления",
- "settings.restore.restarting": "Сервер перезапускается...",
- "settings.restore.restart_timeout": "Сервер не отвечает. Обновите страницу вручную.",
- "settings.restart_server": "Перезапустить сервер",
- "settings.restart_confirm": "Перезапустить сервер? Активные цели будут остановлены.",
- "settings.restarting": "Перезапуск сервера...",
- "settings.button.close": "Закрыть",
- "settings.log_level.label": "Уровень логирования",
- "settings.log_level.hint": "Изменить подробность логов сервера в реальном времени. DEBUG — максимум деталей, CRITICAL — только критические ошибки.",
- "settings.log_level.save": "Применить",
- "settings.log_level.saved": "Уровень логирования изменён",
- "settings.log_level.save_error": "Не удалось изменить уровень логирования",
- "settings.log_level.desc.debug": "Подробный вывод для разработки",
- "settings.log_level.desc.info": "Обычные сообщения",
- "settings.log_level.desc.warning": "Возможные проблемы",
- "settings.log_level.desc.error": "Только ошибки",
- "settings.log_level.desc.critical": "Только критические ошибки",
- "settings.auto_backup.label": "Авто-бэкап",
- "settings.auto_backup.hint": "Автоматическое создание периодических резервных копий конфигурации. Старые копии удаляются при превышении максимального количества.",
- "settings.auto_backup.enable": "Включить авто-бэкап",
- "settings.auto_backup.interval_label": "Интервал",
- "settings.auto_backup.max_label": "Макс. копий",
- "settings.auto_backup.save": "Сохранить настройки",
- "settings.auto_backup.saved": "Настройки авто-бэкапа сохранены",
- "settings.auto_backup.save_error": "Не удалось сохранить настройки авто-бэкапа",
- "settings.auto_backup.last_backup": "Последний бэкап",
- "settings.auto_backup.never": "Никогда",
- "settings.saved_backups.label": "Сохранённые копии",
- "settings.saved_backups.hint": "Файлы авто-бэкапа на сервере. Скачайте для локального хранения или удалите для освобождения места.",
- "settings.saved_backups.empty": "Нет сохранённых копий",
- "settings.saved_backups.restore": "Восстановить",
- "settings.saved_backups.download": "Скачать",
- "settings.saved_backups.delete": "Удалить",
- "settings.saved_backups.delete_confirm": "Удалить эту резервную копию?",
- "settings.saved_backups.delete_error": "Не удалось удалить копию",
- "settings.saved_backups.type.auto": "авто",
- "settings.saved_backups.type.manual": "ручной",
- "settings.mqtt.label": "MQTT",
- "settings.mqtt.hint": "Настройте подключение к MQTT-брокеру для условий и триггеров автоматизации.",
- "settings.mqtt.enabled": "Включить MQTT",
- "settings.mqtt.host_label": "Хост брокера",
- "settings.mqtt.port_label": "Порт",
- "settings.mqtt.username_label": "Имя пользователя",
- "settings.mqtt.password_label": "Пароль",
- "settings.mqtt.password_set_hint": "Пароль задан — оставьте пустым, чтобы сохранить",
- "settings.mqtt.client_id_label": "Идентификатор клиента",
- "settings.mqtt.base_topic_label": "Базовый топик",
- "settings.mqtt.save": "Сохранить настройки MQTT",
- "settings.mqtt.saved": "Настройки MQTT сохранены",
- "settings.mqtt.save_error": "Не удалось сохранить настройки MQTT",
- "settings.mqtt.error_host_required": "Требуется указать хост брокера",
- "settings.logs.label": "Журнал сервера",
- "settings.logs.hint": "Просмотр журнала сервера в реальном времени. Используйте фильтр для отображения нужных уровней.",
- "settings.logs.connect": "Подключить",
- "settings.logs.disconnect": "Отключить",
- "settings.logs.clear": "Очистить",
- "settings.logs.error": "Ошибка подключения к журналу",
- "settings.logs.filter.all": "Все уровни",
- "settings.logs.filter.info": "Info+",
- "settings.logs.filter.warning": "Warning+",
- "settings.logs.filter.error": "Только ошибки",
- "settings.logs.filter.all_desc": "Все сообщения лога",
- "settings.logs.filter.info_desc": "Info, предупреждения и ошибки",
- "settings.logs.filter.warning_desc": "Только предупреждения и ошибки",
- "settings.logs.filter.error_desc": "Только ошибки",
- "device.error.power_off_failed": "Не удалось выключить устройство",
- "device.removed": "Устройство удалено",
- "device.error.remove_failed": "Не удалось удалить устройство",
- "device.error.settings_load_failed": "Не удалось загрузить настройки устройства",
- "device.error.brightness": "Не удалось обновить яркость",
- "device.error.required": "Пожалуйста, заполните все поля",
- "device.error.update": "Не удалось обновить устройство",
- "device.error.save": "Не удалось сохранить настройки",
- "device.error.clone_failed": "Не удалось клонировать устройство",
- "device_discovery.error.fill_all_fields": "Пожалуйста, заполните все поля",
- "device_discovery.added": "Устройство успешно добавлено",
- "device_discovery.error.add_failed": "Не удалось добавить устройство",
- "calibration.error.load_failed": "Не удалось загрузить калибровку",
- "calibration.error.css_load_failed": "Не удалось загрузить источник цветовой полосы",
- "calibration.error.test_toggle_failed": "Не удалось переключить тестовый край",
- "calibration.saved": "Калибровка сохранена",
- "calibration.error.save_failed": "Не удалось сохранить калибровку",
- "calibration.error.led_count_mismatch": "Общее количество LED должно совпадать с количеством LED устройства",
- "calibration.error.led_count_exceeded": "Калиброванных LED больше, чем общее количество LED",
- "calibration.mode.simple": "Простой",
- "calibration.mode.advanced": "Расширенный",
- "calibration.switch_to_advanced": "Расширенный режим",
- "calibration.advanced.title": "Расширенная калибровка",
- "calibration.advanced.switch_to_simple": "Простой режим",
- "calibration.advanced.lines_title": "Линии",
- "calibration.advanced.canvas_hint": "Перетаскивайте мониторы. Нажимайте на грани для выбора линий. Прокрутка — масштаб, перетаскивание пустого места — сдвиг.",
- "calibration.advanced.reset_view": "Сбросить вид",
- "calibration.advanced.line_properties": "Свойства линии",
- "calibration.advanced.picture_source": "Источник:",
- "calibration.advanced.picture_source.hint": "Источник изображения (монитор), с которого эта линия снимает данные",
- "calibration.advanced.edge": "Грань:",
- "calibration.advanced.edge.hint": "С какой грани экрана снимать пиксели",
- "calibration.advanced.led_count": "Светодиоды:",
- "calibration.advanced.led_count.hint": "Количество светодиодов на этой линии",
- "calibration.advanced.span_start": "Начало:",
- "calibration.advanced.span_start.hint": "Откуда начинается захват вдоль грани (0 = начало, 1 = конец). Позволяет покрыть только часть грани.",
- "calibration.advanced.span_end": "Конец:",
- "calibration.advanced.span_end.hint": "Где заканчивается захват вдоль грани (0 = начало, 1 = конец). Вместе с «Начало» определяет активный участок.",
- "calibration.advanced.border_width": "Глубина (пкс):",
- "calibration.advanced.border_width.hint": "Сколько пикселей вглубь от края захватывать. Большие значения берут больше внутренней части экрана.",
- "calibration.advanced.reverse": "Реверс",
- "calibration.advanced.no_lines_warning": "Добавьте хотя бы одну линию",
- "dashboard.error.automation_toggle_failed": "Не удалось переключить автоматизацию",
- "dashboard.error.start_failed": "Не удалось запустить обработку",
- "dashboard.error.stop_failed": "Не удалось остановить обработку",
- "dashboard.error.stop_all": "Не удалось остановить все цели",
- "target.error.editor_open_failed": "Не удалось открыть редактор цели",
- "target.error.start_failed": "Не удалось запустить цель",
- "target.error.stop_failed": "Не удалось остановить цель",
- "target.error.clone_failed": "Не удалось клонировать цель",
- "target.error.delete_failed": "Не удалось удалить цель",
- "targets.stop_all.button": "Остановить все",
- "targets.stop_all.none_running": "Нет запущенных целей",
- "targets.stop_all.stopped": "Остановлено целей: {count}",
- "targets.stop_all.error": "Не удалось остановить цели",
- "audio_source.error.load": "Не удалось загрузить аудиоисточник",
- "audio_template.error.clone_failed": "Не удалось клонировать аудиошаблон",
- "value_source.error.load": "Не удалось загрузить источник значений",
- "color_strip.error.editor_open_failed": "Не удалось открыть редактор цветовой полосы",
- "color_strip.error.clone_failed": "Не удалось клонировать источник цветовой полосы",
- "color_strip.error.delete_failed": "Не удалось удалить источник цветовой полосы",
- "pattern.error.editor_open_failed": "Не удалось открыть редактор шаблона узоров",
- "pattern.error.clone_failed": "Не удалось клонировать шаблон узоров",
- "pattern.error.delete_failed": "Не удалось удалить шаблон узоров",
- "pattern.error.capture_bg_failed": "Не удалось захватить фон",
- "stream.error.clone_picture_failed": "Не удалось клонировать источник изображения",
- "stream.error.clone_capture_failed": "Не удалось клонировать шаблон захвата",
- "stream.error.clone_pp_failed": "Не удалось клонировать шаблон постобработки",
- "kc_target.error.editor_open_failed": "Не удалось открыть редактор ключевых цветов",
- "kc_target.error.clone_failed": "Не удалось клонировать цель ключевых цветов",
- "kc_target.error.delete_failed": "Не удалось удалить цель ключевых цветов",
- "theme.switched.dark": "Переключено на тёмную тему",
- "theme.switched.light": "Переключено на светлую тему",
- "accent.color.updated": "Цвет акцента обновлён",
- "search.footer": "↑↓ навигация · Enter выбор · Esc закрыть",
- "sync_clock.group.title": "Часы синхронизации",
- "sync_clock.add": "Добавить часы",
- "sync_clock.edit": "Редактировать часы",
- "sync_clock.name": "Название:",
- "sync_clock.name.placeholder": "Основные часы анимации",
- "sync_clock.name.hint": "Описательное название для этих часов синхронизации",
- "sync_clock.speed": "Скорость:",
- "sync_clock.speed.hint": "Множитель скорости анимации для всех привязанных источников. 1.0 = обычная, 2.0 = двойная, 0.5 = половинная.",
- "sync_clock.description": "Описание (необязательно):",
- "sync_clock.description.placeholder": "Необязательное описание",
- "sync_clock.description.hint": "Необязательные заметки о назначении этих часов",
- "sync_clock.status.running": "Работает",
- "sync_clock.status.paused": "Приостановлено",
- "sync_clock.action.pause": "Приостановить",
- "sync_clock.action.resume": "Возобновить",
- "sync_clock.action.reset": "Сбросить",
- "sync_clock.error.name_required": "Название часов обязательно",
- "sync_clock.error.load": "Не удалось загрузить часы синхронизации",
- "sync_clock.created": "Часы синхронизации созданы",
- "sync_clock.updated": "Часы синхронизации обновлены",
- "sync_clock.deleted": "Часы синхронизации удалены",
- "sync_clock.paused": "Часы приостановлены",
- "sync_clock.resumed": "Часы возобновлены",
- "sync_clock.reset_done": "Часы сброшены на ноль",
- "sync_clock.delete.confirm": "Удалить эти часы синхронизации? Привязанные источники потеряют синхронизацию и будут работать на скорости по умолчанию.",
- "sync_clock.elapsed": "Прошло времени",
- "color_strip.clock": "Часы синхронизации:",
- "color_strip.clock.hint": "Привязка к часам для синхронизации анимации между источниками. Скорость управляется на часах.",
- "graph.title": "Граф",
- "graph.fit_all": "Показать все узлы",
- "graph.zoom_in": "Приблизить",
- "graph.zoom_out": "Отдалить",
- "graph.search": "Поиск узлов",
- "graph.search_placeholder": "Поиск сущностей...",
- "graph.legend": "Легенда",
- "graph.minimap": "Миникарта",
- "graph.relayout": "Перестроить",
- "graph.empty": "Ещё нет сущностей",
- "graph.empty.hint": "Создайте устройства, источники и цели, чтобы увидеть их здесь.",
- "graph.disconnect": "Отключить",
- "graph.connection_updated": "Соединение обновлено",
- "graph.connection_failed": "Не удалось обновить соединение",
- "graph.connection_removed": "Соединение удалено",
- "graph.disconnect_failed": "Не удалось отключить",
- "graph.relayout_confirm": "Сбросить все ручные позиции узлов и перестроить граф?",
- "graph.fullscreen": "Полноэкранный режим",
- "graph.add_entity": "Добавить сущность",
- "graph.color_picker": "Цвет узла",
- "graph.filter": "Фильтр узлов",
- "graph.filter_placeholder": "Фильтр по имени...",
- "graph.filter_clear": "Очистить фильтр",
- "graph.filter_running": "Запущен",
- "graph.filter_stopped": "Остановлен",
- "graph.filter_types": "Типы",
- "graph.filter_group.capture": "Захват",
- "graph.filter_group.strip": "Цвет. полосы",
- "graph.filter_group.audio": "Аудио",
- "graph.filter_group.targets": "Цели",
- "graph.filter_group.other": "Другое",
- "graph.bulk_delete_confirm": "Удалить {count} выбранных сущностей?",
- "graph.nothing_to_undo": "Нечего отменять",
- "graph.nothing_to_redo": "Нечего повторять",
- "graph.help_title": "Горячие клавиши",
- "graph.help.search": "Поиск",
- "graph.help.filter": "Фильтр",
- "graph.help.add": "Добавить сущность",
- "graph.help.shortcuts": "Горячие клавиши",
- "graph.help.delete": "Удалить / Отсоединить",
- "graph.help.select_all": "Выбрать все",
- "graph.help.undo": "Отменить",
- "graph.help.redo": "Повторить",
- "graph.help.fullscreen": "Полный экран",
- "graph.help.deselect": "Снять выбор",
- "graph.help.navigate": "Навигация по узлам",
- "graph.help.click": "Клик",
- "graph.help.click_desc": "Выбрать узел",
- "graph.help.dblclick": "Двойной клик",
- "graph.help.dblclick_desc": "Приблизить к узлу",
- "graph.help.shift_click": "Shift+Клик",
- "graph.help.shift_click_desc": "Множественный выбор",
- "graph.help.shift_drag": "Shift+Перетащить",
- "graph.help.shift_drag_desc": "Выбор рамкой",
- "graph.help.drag_node": "Перетащить узел",
- "graph.help.drag_node_desc": "Переместить",
- "graph.help.drag_port": "Перетащить порт",
- "graph.help.drag_port_desc": "Соединить сущности",
- "graph.help.right_click": "ПКМ по связи",
- "graph.help.right_click_desc": "Отсоединить связь",
- "graph.tooltip.fps": "FPS",
- "graph.tooltip.errors": "Ошибки",
- "graph.tooltip.uptime": "Время работы",
- "automation.enabled": "Автоматизация включена",
- "automation.disabled": "Автоматизация выключена",
- "scene_preset.activated": "Пресет активирован",
- "scene_preset.used_by": "Используется в %d автоматизации(ях)",
- "settings.api_keys.label": "API-ключи",
- "settings.api_keys.hint": "API-ключи определяются в конфигурационном файле сервера (config.yaml). Отредактируйте файл и перезапустите сервер для применения изменений.",
- "settings.api_keys.empty": "API-ключи не настроены",
- "settings.api_keys.load_error": "Не удалось загрузить API-ключи",
- "settings.partial.label": "Частичный экспорт / импорт",
- "settings.partial.hint": "Экспортировать или импортировать один тип объектов. Импорт заменяет или объединяет данные и перезапускает сервер.",
- "settings.partial.store.devices": "Устройства",
- "settings.partial.store.output_targets": "LED-цели",
- "settings.partial.store.color_strip_sources": "Цветные полосы",
- "settings.partial.store.picture_sources": "Источники изображений",
- "settings.partial.store.audio_sources": "Аудио-источники",
- "settings.partial.store.audio_templates": "Аудио-шаблоны",
- "settings.partial.store.capture_templates": "Шаблоны захвата",
- "settings.partial.store.postprocessing_templates": "Шаблоны постобработки",
- "settings.partial.store.color_strip_processing_templates": "Шаблоны обработки полос",
- "settings.partial.store.pattern_templates": "Шаблоны паттернов",
- "settings.partial.store.value_sources": "Источники значений",
- "settings.partial.store.sync_clocks": "Синхронные часы",
- "settings.partial.store.automations": "Автоматизации",
- "settings.partial.store.scene_presets": "Пресеты сцен",
- "settings.partial.export_button": "Экспорт",
- "settings.partial.import_button": "Импорт из файла",
- "settings.partial.merge_label": "Объединить (добавить/перезаписать, сохранить существующие)",
- "settings.partial.export_success": "Экспорт выполнен",
- "settings.partial.export_error": "Ошибка экспорта",
- "settings.partial.import_success": "Импорт выполнен",
- "settings.partial.import_error": "Ошибка импорта",
- "settings.partial.import_confirm_replace": "Это ЗАМЕНИТ все данные {store} и перезапустит сервер. Продолжить?",
- "settings.partial.import_confirm_merge": "Это ОБЪЕДИНИТ данные {store} и перезапустит сервер. Продолжить?",
- "section.empty.devices": "Устройств пока нет. Нажмите + для добавления.",
- "section.empty.targets": "LED-целей пока нет. Нажмите + для добавления.",
- "section.empty.kc_targets": "Целей ключевых цветов пока нет. Нажмите + для добавления.",
- "section.empty.pattern_templates": "Шаблонов паттернов пока нет. Нажмите + для добавления.",
- "section.empty.picture_sources": "Источников пока нет. Нажмите + для добавления.",
- "section.empty.capture_templates": "Шаблонов захвата пока нет. Нажмите + для добавления.",
- "section.empty.pp_templates": "Шаблонов постобработки пока нет. Нажмите + для добавления.",
- "section.empty.audio_sources": "Аудио-источников пока нет. Нажмите + для добавления.",
- "section.empty.audio_templates": "Аудио-шаблонов пока нет. Нажмите + для добавления.",
- "section.empty.color_strips": "Цветных полос пока нет. Нажмите + для добавления.",
- "section.empty.value_sources": "Источников значений пока нет. Нажмите + для добавления.",
- "section.empty.sync_clocks": "Синхронных часов пока нет. Нажмите + для добавления.",
- "section.empty.cspt": "Шаблонов обработки полос пока нет. Нажмите + для добавления.",
- "section.empty.automations": "Автоматизаций пока нет. Нажмите + для добавления.",
- "section.empty.scenes": "Пресетов сцен пока нет. Нажмите + для добавления.",
-
- "bulk.select": "Выбрать",
- "bulk.cancel": "Отмена",
- "bulk.selected_count.one": "{count} выбран",
- "bulk.selected_count.few": "{count} выбрано",
- "bulk.selected_count.many": "{count} выбрано",
- "bulk.select_all": "Выбрать все",
- "bulk.deselect_all": "Снять выбор",
- "bulk.delete": "Удалить",
- "bulk.start": "Запустить",
- "bulk.stop": "Остановить",
- "bulk.enable": "Включить",
- "bulk.disable": "Выключить",
- "bulk.confirm_delete.one": "Удалить {count} элемент?",
- "bulk.confirm_delete.few": "Удалить {count} элемента?",
- "bulk.confirm_delete.many": "Удалить {count} элементов?"
-}
+ "app.title": "LED Grab",
+ "app.version": "Версия:",
+ "app.api_docs": "Документация API",
+ "app.connection_lost": "Сервер недоступен",
+ "app.connection_retrying": "Попытка переподключения…",
+ "demo.badge": "ДЕМО",
+ "demo.banner": "Вы в демо-режиме — все устройства и данные виртуальные. Реальное оборудование не используется.",
+ "theme.toggle": "Переключить тему",
+ "bg.anim.toggle": "Анимированный фон",
+ "accent.title": "Цвет акцента",
+ "accent.custom": "Свой",
+ "accent.reset": "Сброс",
+ "locale.change": "Изменить язык",
+ "auth.login": "Войти",
+ "auth.logout": "Выйти",
+ "auth.authenticated": "● Авторизован",
+ "auth.title": "Вход в LED Grab",
+ "auth.message": "Пожалуйста, введите ваш API ключ для аутентификации и доступа к LED Grab.",
+ "auth.label": "API Ключ:",
+ "auth.placeholder": "Введите ваш API ключ...",
+ "auth.hint": "Ваш API ключ будет безопасно сохранен в локальном хранилище браузера.",
+ "auth.button.cancel": "Отмена",
+ "auth.button.login": "Войти",
+ "auth.error.required": "Пожалуйста, введите API ключ",
+ "auth.success": "Вход выполнен успешно!",
+ "auth.logout.confirm": "Вы уверены, что хотите выйти?",
+ "auth.logout.success": "Выход выполнен успешно",
+ "auth.please_login": "Пожалуйста, войдите для просмотра",
+ "auth.session_expired": "Ваша сессия истекла или API ключ недействителен. Пожалуйста, войдите снова.",
+ "auth.toggle_password": "Показать/скрыть пароль",
+ "auth.prompt_enter": "Enter your API key:",
+ "auth.prompt_update": "Current API key is set. Enter new key to update or leave blank to remove:",
+ "api_key.login": "Войти",
+ "displays.title": "Доступные Дисплеи",
+ "displays.layout": "Дисплеи",
+ "displays.information": "Информация о Дисплеях",
+ "displays.legend.primary": "Основной Дисплей",
+ "displays.legend.secondary": "Вторичный Дисплей",
+ "displays.badge.primary": "Основной",
+ "displays.badge.secondary": "Вторичный",
+ "displays.resolution": "Разрешение:",
+ "displays.refresh_rate": "Частота Обновления:",
+ "displays.position": "Позиция:",
+ "displays.index": "Индекс Дисплея:",
+ "displays.loading": "Загрузка дисплеев...",
+ "displays.none": "Нет доступных дисплеев",
+ "displays.failed": "Не удалось загрузить дисплеи",
+ "displays.picker.title": "Выберите Дисплей",
+ "displays.picker.title.device": "Выберите Устройство",
+ "displays.picker.select": "Выберите дисплей...",
+ "displays.picker.click_to_select": "Нажмите, чтобы выбрать этот дисплей",
+ "displays.picker.adb_connect": "Подключить ADB устройство",
+ "displays.picker.adb_connect.placeholder": "IP адрес (напр. 192.168.2.201)",
+ "displays.picker.adb_connect.button": "Подключить",
+ "displays.picker.adb_connect.success": "Устройство подключено",
+ "displays.picker.adb_connect.error": "Не удалось подключить устройство",
+ "displays.picker.adb_disconnect": "Отключить",
+ "displays.picker.no_android": "Android устройства не найдены. Подключите по USB или введите IP выше.",
+ "templates.title": "Шаблоны Движков",
+ "templates.description": "Шаблоны захвата определяют, как захватывается экран. Каждый шаблон использует определённый движок захвата (MSS, DXcam, WGC) с настраиваемыми параметрами. Назначайте шаблоны устройствам для оптимальной производительности.",
+ "templates.loading": "Загрузка шаблонов...",
+ "templates.empty": "Шаблоны захвата не настроены",
+ "templates.add": "Добавить Шаблон Движка",
+ "templates.edit": "Редактировать Шаблон Движка",
+ "templates.name": "Имя Шаблона:",
+ "templates.name.placeholder": "Мой Пользовательский Шаблон",
+ "templates.description.label": "Описание (необязательно):",
+ "templates.description.placeholder": "Опишите этот шаблон...",
+ "templates.engine": "Движок Захвата:",
+ "templates.engine.hint": "Выберите технологию захвата экрана",
+ "templates.engine.select": "Выберите движок...",
+ "templates.engine.unavailable": "Недоступен",
+ "templates.engine.unavailable.hint": "Этот движок недоступен в вашей системе",
+ "templates.engine.mss.desc": "Кроссплатформенный, чистый Python",
+ "templates.engine.dxcam.desc": "DirectX, низкая задержка",
+ "templates.engine.bettercam.desc": "DirectX, высокая производительность",
+ "templates.engine.camera.desc": "Захват USB/IP камеры",
+ "templates.engine.scrcpy.desc": "Зеркалирование экрана Android",
+ "templates.engine.wgc.desc": "Windows Graphics Capture",
+ "templates.config": "Конфигурация",
+ "templates.config.show": "Показать конфигурацию",
+ "templates.config.none": "Нет дополнительных настроек",
+ "templates.config.default": "По умолчанию",
+ "templates.config.camera_backend.auto": "Автовыбор лучшего бэкенда",
+ "templates.config.camera_backend.dshow": "Windows DirectShow",
+ "templates.config.camera_backend.msmf": "Windows Media Foundation",
+ "templates.config.camera_backend.v4l2": "Linux Video4Linux2",
+ "templates.created": "Шаблон успешно создан",
+ "templates.updated": "Шаблон успешно обновлён",
+ "templates.deleted": "Шаблон успешно удалён",
+ "templates.delete.confirm": "Вы уверены, что хотите удалить этот шаблон?",
+ "templates.error.load": "Не удалось загрузить шаблоны",
+ "templates.error.engines": "Не удалось загрузить движки",
+ "templates.error.required": "Пожалуйста, заполните все обязательные поля",
+ "templates.error.delete": "Не удалось удалить шаблон",
+ "templates.test.title": "Тест Захвата",
+ "templates.test.description": "Протестируйте этот шаблон перед сохранением, чтобы увидеть предпросмотр захвата и метрики производительности.",
+ "templates.test.display": "Дисплей:",
+ "templates.test.display.select": "Выберите дисплей...",
+ "templates.test.duration": "Длительность Захвата (с):",
+ "templates.test.border_width": "Ширина Границы (px):",
+ "templates.test.run": "Запустить",
+ "templates.test.running": "Выполняется тест...",
+ "templates.test.results.preview": "Полный Предпросмотр Захвата",
+ "templates.test.results.borders": "Извлечение Границ",
+ "templates.test.results.top": "Сверху",
+ "templates.test.results.right": "Справа",
+ "templates.test.results.bottom": "Снизу",
+ "templates.test.results.left": "Слева",
+ "templates.test.results.performance": "Производительность",
+ "templates.test.results.capture_time": "Захват",
+ "templates.test.results.extraction_time": "Извлечение",
+ "templates.test.results.total_time": "Всего",
+ "templates.test.results.max_fps": "Макс. FPS",
+ "templates.test.results.duration": "Длительность",
+ "templates.test.results.frame_count": "Кадры",
+ "templates.test.results.actual_fps": "Факт. FPS",
+ "templates.test.results.avg_capture_time": "Средн. Захват",
+ "templates.test.results.resolution": "Разрешение:",
+ "templates.test.error.no_engine": "Пожалуйста, выберите движок захвата",
+ "templates.test.error.no_display": "Пожалуйста, выберите дисплей",
+ "templates.test.error.failed": "Тест не удался",
+ "devices.title": "Устройства",
+ "device.select_type": "Выберите тип устройства",
+ "devices.add": "Добавить Новое Устройство",
+ "devices.loading": "Загрузка устройств...",
+ "devices.none": "Устройства не настроены",
+ "devices.failed": "Не удалось загрузить устройства",
+ "devices.wled_config": "Конфигурация WLED:",
+ "devices.wled_note": "Настройте ваше WLED устройство (эффекты, сегменты, порядок цветов, ограничения питания и т.д.) используя",
+ "devices.wled_link": "официальное приложение WLED",
+ "devices.wled_note_or": "или встроенный",
+ "devices.wled_webui_link": "веб-интерфейс WLED",
+ "devices.wled_note_webui": "(откройте IP устройства в браузере).",
+ "devices.wled_note2": "Этот контроллер отправляет данные о цвете пикселей и управляет яркостью для каждого устройства.",
+ "device.scan": "Автопоиск",
+ "device.scan.empty": "Устройства не найдены",
+ "device.scan.error": "Ошибка сканирования сети",
+ "device.scan.already_added": "Уже добавлено",
+ "device.scan.selected": "Устройство выбрано",
+ "device.type": "Тип устройства:",
+ "device.type.hint": "Выберите тип LED контроллера",
+ "device.type.wled": "WLED",
+ "device.type.wled.desc": "WiFi LED контроллер по HTTP/UDP",
+ "device.type.adalight": "Adalight",
+ "device.type.adalight.desc": "Серийный протокол для Arduino",
+ "device.type.ambiled": "AmbiLED",
+ "device.type.ambiled.desc": "Серийный протокол AmbiLED",
+ "device.type.mqtt": "MQTT",
+ "device.type.mqtt.desc": "Отправка LED данных через MQTT брокер",
+ "device.type.ws": "WebSocket",
+ "device.type.ws.desc": "Стриминг LED данных через WebSocket",
+ "device.type.openrgb": "OpenRGB",
+ "device.type.openrgb.desc": "Управление RGB через OpenRGB",
+ "device.type.dmx": "DMX",
+ "device.type.dmx.desc": "Art-Net / sACN (E1.31) сценическое освещение",
+ "device.type.mock": "Mock",
+ "device.type.mock.desc": "Виртуальное устройство для тестов",
+ "device.type.espnow": "ESP-NOW",
+ "device.type.espnow.desc": "Ultra-low-latency via ESP32 gateway",
+ "device.type.hue": "Philips Hue",
+ "device.type.hue.desc": "Hue Entertainment API streaming",
+ "device.type.usbhid": "USB HID",
+ "device.type.usbhid.desc": "USB RGB peripherals (keyboards, mice)",
+ "device.type.spi": "SPI Direct",
+ "device.type.spi.desc": "Raspberry Pi GPIO/SPI LED strips",
+ "device.type.chroma": "Razer Chroma",
+ "device.type.chroma.desc": "Razer peripherals via Chroma SDK",
+ "device.type.gamesense": "SteelSeries",
+ "device.type.gamesense.desc": "SteelSeries peripherals via GameSense",
+ "device.chroma.device_type": "Peripheral Type:",
+ "device.chroma.device_type.hint": "Which Razer peripheral to control via Chroma SDK",
+ "device.gamesense.device_type": "Peripheral Type:",
+ "device.gamesense.device_type.hint": "Which SteelSeries peripheral to control via GameSense",
+ "device.espnow.peer_mac": "Peer MAC:",
+ "device.espnow.peer_mac.hint": "MAC address of the remote ESP32 receiver (e.g. AA:BB:CC:DD:EE:FF)",
+ "device.espnow.channel": "WiFi Channel:",
+ "device.espnow.channel.hint": "WiFi channel (1-14). Must match the receiver's channel.",
+ "device.hue.url": "Bridge IP:",
+ "device.hue.url.hint": "IP address of your Hue bridge",
+ "device.hue.username": "Bridge Username:",
+ "device.hue.username.hint": "Hue bridge application key from pairing",
+ "device.hue.client_key": "Client Key:",
+ "device.hue.client_key.hint": "Entertainment API client key (hex string from pairing)",
+ "device.hue.group_id": "Entertainment Group:",
+ "device.hue.group_id.hint": "Entertainment configuration ID from your Hue bridge",
+ "device.usbhid.url": "VID:PID:",
+ "device.usbhid.url.hint": "USB Vendor:Product ID in hex (e.g. 1532:0084)",
+ "device.spi.url": "GPIO/SPI Path:",
+ "device.spi.url.hint": "GPIO pin or SPI device path (e.g. spi://gpio:18)",
+ "device.spi.speed": "SPI Speed (Hz):",
+ "device.spi.speed.hint": "SPI clock speed. 800000 Hz for WS2812, 2400000 Hz for APA102.",
+ "device.spi.led_type": "LED Chipset:",
+ "device.spi.led_type.hint": "Type of addressable LED strip connected to the GPIO/SPI pin",
+ "device.spi.led_type.ws2812b.desc": "Most common, 800 KHz data, 3-wire RGB",
+ "device.spi.led_type.ws2812.desc": "Original WS2812, 800 KHz, 3-wire RGB",
+ "device.spi.led_type.ws2811.desc": "External driver IC, 400 KHz, 12V strips",
+ "device.spi.led_type.sk6812.desc": "Samsung LED, 800 KHz, 3-wire RGB",
+ "device.spi.led_type.sk6812_rgbw.desc": "SK6812 with dedicated white channel",
+ "device.gamesense.peripheral.keyboard": "Keyboard",
+ "device.gamesense.peripheral.keyboard.desc": "Per-key RGB illumination",
+ "device.gamesense.peripheral.mouse": "Mouse",
+ "device.gamesense.peripheral.mouse.desc": "Mouse RGB zones",
+ "device.gamesense.peripheral.headset": "Headset",
+ "device.gamesense.peripheral.headset.desc": "Headset earcup lighting",
+ "device.gamesense.peripheral.mousepad": "Mousepad",
+ "device.gamesense.peripheral.mousepad.desc": "Mousepad edge lighting zones",
+ "device.gamesense.peripheral.indicator": "Indicator",
+ "device.gamesense.peripheral.indicator.desc": "OLED/LED status indicator",
+ "device.dmx_protocol": "Протокол DMX:",
+ "device.dmx_protocol.hint": "Art-Net использует UDP порт 6454, sACN (E1.31) — UDP порт 5568",
+ "device.dmx_protocol.artnet.desc": "UDP unicast, порт 6454",
+ "device.dmx_protocol.sacn.desc": "Multicast/unicast, порт 5568",
+ "device.dmx_start_universe": "Начальный Universe:",
+ "device.dmx_start_universe.hint": "Первый DMX-юниверс (0-32767). Дополнительные юниверсы используются автоматически при >170 светодиодах.",
+ "device.dmx_start_channel": "Начальный канал:",
+ "device.dmx_start_channel.hint": "Первый DMX-канал в юниверсе (1-512)",
+ "device.dmx.url": "IP адрес:",
+ "device.dmx.url.hint": "IP адрес DMX-узла (напр. 192.168.1.50)",
+ "device.dmx.url.placeholder": "192.168.1.50",
+ "device.serial_port": "Серийный порт:",
+ "device.serial_port.hint": "Выберите COM порт устройства Adalight",
+ "device.serial_port.none": "Серийные порты не найдены",
+ "device.serial_port.select": "Выберите порт...",
+ "device.led_count_manual.hint": "Количество светодиодов на ленте (должно совпадать с вашим скетчем Arduino)",
+ "device.baud_rate": "Скорость порта:",
+ "device.baud_rate.hint": "Скорость серийного соединения. Выше = больше FPS, но требует соответствия скетчу Arduino.",
+ "device.led_type": "Тип LED:",
+ "device.led_type.hint": "RGB (3 канала) или RGBW (4 канала с выделенным белым)",
+ "device.send_latency": "Задержка отправки (мс):",
+ "device.send_latency.hint": "Имитация сетевой/серийной задержки на кадр в миллисекундах",
+ "device.css_processing_template": "Шаблон Обработки Полос:",
+ "device.css_processing_template.hint": "Шаблон обработки по умолчанию, применяемый ко всем цветовым полосам на этом устройстве",
+ "device.mqtt_topic": "MQTT Топик:",
+ "device.mqtt_topic.hint": "MQTT топик для публикации пиксельных данных (напр. mqtt://ledgrab/device/name)",
+ "device.mqtt_topic.placeholder": "mqtt://ledgrab/device/гостиная",
+ "device.ws_url": "URL подключения:",
+ "device.ws_url.hint": "WebSocket URL для подключения клиентов и получения LED данных",
+ "device.openrgb.url": "OpenRGB URL:",
+ "device.openrgb.url.hint": "Адрес сервера OpenRGB (напр. openrgb://localhost:6742/0)",
+ "device.openrgb.zone": "Зоны:",
+ "device.openrgb.zone.hint": "Выберите зоны LED для управления (оставьте все неотмеченными для всех зон)",
+ "device.openrgb.zone.loading": "Загрузка зон…",
+ "device.openrgb.zone.error": "Не удалось загрузить зоны",
+ "device.openrgb.mode": "Режим зон:",
+ "device.openrgb.mode.hint": "Объединённый — все зоны как одна непрерывная LED-лента. Раздельный — каждая зона независимо отображает полный эффект.",
+ "device.openrgb.mode.combined": "Объединённая лента",
+ "device.openrgb.mode.separate": "Независимые зоны",
+ "device.openrgb.added_multiple": "Добавлено {count} устройств",
+ "device.url.hint": "IP адрес или имя хоста устройства (напр. http://192.168.1.100)",
+ "device.name": "Имя Устройства:",
+ "device.name.placeholder": "ТВ в Гостиной",
+ "device.url": "URL:",
+ "device.url.placeholder": "http://192.168.1.100",
+ "device.led_count": "Количество Светодиодов:",
+ "device.led_count.hint": "Количество светодиодов, настроенных в устройстве",
+ "device.led_count.hint.auto": "Автоматически определяется из устройства",
+ "device.button.add": "Добавить Устройство",
+ "device.button.start": "Запустить",
+ "device.button.stop": "Остановить",
+ "device.button.settings": "Основные настройки",
+ "device.button.capture_settings": "Настройки захвата",
+ "device.button.calibrate": "Калибровка",
+ "device.button.remove": "Удалить",
+ "device.button.webui": "Открыть веб-интерфейс устройства",
+ "device.button.power_off": "Выключить",
+ "device.button.ping": "Пинг устройства",
+ "device.ping.online": "Онлайн ({ms}мс)",
+ "device.ping.offline": "Устройство недоступно",
+ "device.ping.error": "Ошибка пинга",
+ "device.power.off_success": "Устройство выключено",
+ "device.status.connected": "Подключено",
+ "device.status.disconnected": "Отключено",
+ "device.status.error": "Ошибка",
+ "device.status.processing": "Обработка",
+ "device.status.idle": "Ожидание",
+ "device.fps": "FPS:",
+ "device.display": "Дисплей:",
+ "device.remove.confirm": "Вы уверены, что хотите удалить это устройство?",
+ "device.added": "Устройство успешно добавлено",
+ "device.removed": "Устройство удалено",
+ "device.started": "Обработка запущена",
+ "device.stopped": "Обработка остановлена",
+ "device.metrics.actual_fps": "Факт. FPS",
+ "device.metrics.current_fps": "Текущ. FPS",
+ "device.metrics.target_fps": "Целев. FPS",
+ "device.metrics.potential_fps": "Потенц. FPS",
+ "device.metrics.frames": "Кадры",
+ "device.metrics.frames_skipped": "Пропущено",
+ "device.metrics.keepalive": "Keepalive",
+ "device.metrics.errors": "Ошибки",
+ "device.metrics.uptime": "Время работы",
+ "device.metrics.timing": "Тайминг пайплайна:",
+ "device.metrics.device_fps": "Частота обновления устройства",
+ "device.health.online": "Онлайн",
+ "device.health.offline": "Недоступен",
+ "device.health.streaming_unreachable": "Недоступен во время стриминга",
+ "device.health.checking": "Проверка...",
+ "device.last_seen.label": "Последний раз",
+ "device.last_seen.just_now": "только что",
+ "device.last_seen.seconds": "%d с назад",
+ "device.last_seen.minutes": "%d мин назад",
+ "device.last_seen.hours": "%d ч назад",
+ "device.last_seen.days": "%d д назад",
+ "device.tutorial.start": "Начать обучение",
+ "device.tip.metadata": "Информация об устройстве (кол-во LED, тип, цветовые каналы) определяется автоматически",
+ "device.tip.brightness": "Перетащите для регулировки яркости",
+ "device.tip.start": "Запуск или остановка захвата экрана",
+ "device.tip.settings": "Основные настройки устройства (имя, URL, интервал проверки)",
+ "device.tip.capture_settings": "Настройки захвата (дисплей, шаблон захвата)",
+ "device.tip.calibrate": "Калибровка позиций LED, направления и зоны покрытия",
+ "device.tip.webui": "Открыть встроенный веб-интерфейс устройства для расширенной настройки",
+ "device.tip.add": "Нажмите, чтобы добавить новое LED устройство",
+ "settings.title": "Настройки",
+ "settings.tab.general": "Основные",
+ "settings.tab.backup": "Бэкап",
+ "settings.tab.mqtt": "MQTT",
+ "settings.logs.open_viewer": "Открыть логи",
+ "settings.external_url.label": "Внешний URL",
+ "settings.external_url.hint": "Если указан, этот базовый URL используется в URL-ах вебхуков и других пользовательских ссылках вместо автоопределённого локального IP. Пример: https://myserver.example.com:8080",
+ "settings.external_url.placeholder": "https://myserver.example.com:8080",
+ "settings.external_url.save": "Сохранить",
+ "settings.external_url.saved": "Внешний URL сохранён",
+ "settings.external_url.save_error": "Не удалось сохранить внешний URL",
+ "settings.general.title": "Основные Настройки",
+ "settings.capture.title": "Настройки Захвата",
+ "settings.capture.saved": "Настройки захвата обновлены",
+ "settings.capture.failed": "Не удалось сохранить настройки захвата",
+ "settings.brightness": "Яркость:",
+ "settings.brightness.hint": "Общая яркость для этого устройства (0-100%)",
+ "settings.url.hint": "IP адрес или имя хоста устройства",
+ "settings.display_index": "Дисплей:",
+ "settings.display_index.hint": "Какой экран захватывать для этого устройства",
+ "settings.fps": "Целевой FPS:",
+ "settings.fps.hint": "Целевая частота кадров (10-90)",
+ "settings.capture_template": "Шаблон Движка:",
+ "settings.capture_template.hint": "Движок захвата экрана и конфигурация для этого устройства",
+ "settings.button.cancel": "Отмена",
+ "settings.health_interval": "Интервал Проверки (с):",
+ "settings.health_interval.hint": "Как часто проверять статус устройства (5-600 секунд)",
+ "settings.auto_shutdown": "Авто-восстановление:",
+ "settings.auto_shutdown.hint": "Восстанавливать устройство в режим ожидания при остановке целей или сервера",
+ "settings.button.save": "Сохранить Изменения",
+ "settings.saved": "Настройки успешно сохранены",
+ "settings.failed": "Не удалось сохранить настройки",
+ "calibration.title": "Калибровка Светодиодов",
+ "calibration.tip.led_count": "Укажите количество LED на каждой стороне",
+ "calibration.tip.start_corner": "Нажмите на угол для выбора стартовой позиции",
+ "calibration.tip.direction": "Переключение направления ленты (по часовой / против часовой)",
+ "calibration.tip.offset": "Смещение LED — расстояние от LED 0 до стартового угла",
+ "calibration.tip.span": "Перетащите зелёные полосы для настройки зоны покрытия",
+ "calibration.tip.test": "Нажмите на край для теста LED",
+ "calibration.tip.overlay": "Включите оверлей для отображения позиций и нумерации LED на мониторе",
+ "calibration.tip.toggle_inputs": "Нажмите на общее количество LED для скрытия боковых полей",
+ "calibration.tip.border_width": "Сколько пикселей от края экрана использовать для цветов LED",
+ "calibration.tip.skip_leds_start": "Пропуск LED в начале ленты — пропущенные LED остаются выключенными",
+ "calibration.tip.skip_leds_end": "Пропуск LED в конце ленты — пропущенные LED остаются выключенными",
+ "tour.welcome": "Добро пожаловать в LED Grab! Этот краткий тур познакомит вас с интерфейсом. Используйте стрелки или кнопки для навигации.",
+ "tour.dashboard": "Дашборд — обзор запущенных целей, автоматизаций и состояния устройств.",
+ "tour.targets": "Цели — добавляйте WLED-устройства, настраивайте LED-цели с захватом и калибровкой.",
+ "tour.sources": "Источники — управление шаблонами захвата, источниками изображений, звука и цветовых полос.",
+ "tour.graph": "Граф — визуальный обзор всех сущностей и их связей. Перетаскивайте порты для соединения, правый клик по связям для отключения.",
+ "tour.automations": "Автоматизации — автоматизируйте переключение сцен по расписанию, звуку или значениям.",
+ "tour.settings": "Настройки — резервное копирование и восстановление конфигурации.",
+ "tour.api": "API Документация — интерактивная документация REST API на базе Swagger.",
+ "tour.search": "Поиск — быстрый поиск и переход к любому объекту по Ctrl+K.",
+ "tour.theme": "Тема — переключение между тёмной и светлой темой.",
+ "tour.accent": "Цвет акцента — настройте цвет интерфейса по своему вкусу.",
+ "tour.language": "Язык — выберите предпочитаемый язык интерфейса.",
+ "tour.restart": "Запустить тур заново",
+ "tour.dash.perf": "Производительность — графики FPS в реальном времени, метрики задержки и интервал опроса.",
+ "tour.dash.running": "Запущенные цели — метрики стриминга и быстрая остановка.",
+ "tour.dash.stopped": "Остановленные цели — готовы к запуску одним нажатием.",
+ "tour.dash.automations": "Автоматизации — статус активных автоматизаций и быстрое включение/выключение.",
+ "tour.tgt.led_tab": "LED — стандартные LED-цели с настройкой устройств и цветовых полос.",
+ "tour.tgt.devices": "Устройства — ваши LED-контроллеры, найденные в сети.",
+ "tour.tgt.css": "Цветовые полосы — определите, как области экрана соответствуют сегментам LED.",
+ "tour.tgt.targets": "LED-цели — объедините устройство, цветовую полосу и источник захвата для стриминга.",
+ "tour.tgt.kc_tab": "Key Colors — альтернативный тип цели с подбором цветов вместо пиксельного маппинга.",
+ "tour.src.raw": "Raw — источники захвата экрана с ваших дисплеев.",
+ "tour.src.templates": "Шаблоны захвата — переиспользуемые конфигурации (разрешение, FPS, обрезка).",
+ "tour.src.static": "Статичные изображения — тестируйте настройку с файлами изображений.",
+ "tour.src.processed": "Обработка — применяйте эффекты: размытие, яркость, цветокоррекция.",
+ "tour.src.color_strip": "Цветовые полосы — определяют, как области экрана сопоставляются с LED-сегментами.",
+ "tour.src.audio": "Аудио — анализ микрофона или системного звука для реактивных LED-эффектов.",
+ "tour.src.value": "Значения — числовые источники данных для условий автоматизаций.",
+ "tour.src.sync": "Синхро-часы — общие таймеры для синхронизации анимаций между несколькими источниками.",
+ "tour.auto.list": "Автоматизации — автоматизируйте активацию сцен по времени, звуку или значениям.",
+ "tour.auto.add": "Нажмите + для создания новой автоматизации с условиями и сценой для активации.",
+ "tour.auto.card": "Каждая карточка показывает статус автоматизации, условия и кнопки управления.",
+ "tour.auto.scenes_list": "Сцены — сохранённые состояния системы, которые автоматизации могут активировать или вы можете применить вручную.",
+ "tour.auto.scenes_add": "Нажмите + для захвата текущего состояния системы как нового пресета сцены.",
+ "tour.auto.scenes_card": "Каждая карточка сцены показывает количество целей/устройств. Нажмите для редактирования, перезахвата или активации.",
+ "calibration.tutorial.start": "Начать обучение",
+ "calibration.overlay_toggle": "Оверлей",
+ "calibration.start_position": "Начальная Позиция:",
+ "calibration.position.bottom_left": "Нижний Левый",
+ "calibration.position.bottom_right": "Нижний Правый",
+ "calibration.position.top_left": "Верхний Левый",
+ "calibration.position.top_right": "Верхний Правый",
+ "calibration.direction": "Направление:",
+ "calibration.direction.clockwise": "По Часовой Стрелке",
+ "calibration.direction.counterclockwise": "Против Часовой Стрелки",
+ "calibration.leds.top": "Светодиодов Сверху:",
+ "calibration.leds.right": "Светодиодов Справа:",
+ "calibration.leds.bottom": "Светодиодов Снизу:",
+ "calibration.leds.left": "Светодиодов Слева:",
+ "calibration.offset": "Смещение LED:",
+ "calibration.offset.hint": "Расстояние от физического LED 0 до стартового угла (по направлению ленты)",
+ "calibration.skip_start": "Пропуск LED (начало):",
+ "calibration.skip_start.hint": "Количество LED, которые будут выключены в начале ленты (0 = нет)",
+ "calibration.skip_end": "Пропуск LED (конец):",
+ "calibration.skip_end.hint": "Количество LED, которые будут выключены в конце ленты (0 = нет)",
+ "calibration.border_width": "Граница (px):",
+ "calibration.border_width.hint": "Сколько пикселей от края экрана выбирать для цвета LED (1-100)",
+ "calibration.button.cancel": "Отмена",
+ "calibration.button.save": "Сохранить",
+ "calibration.saved": "Калибровка сохранена",
+ "calibration.failed": "Не удалось сохранить калибровку",
+ "server.healthy": "Сервер онлайн",
+ "server.offline": "Сервер офлайн",
+ "error.unauthorized": "Не авторизован - пожалуйста, войдите",
+ "error.network": "Сетевая ошибка",
+ "error.unknown": "Произошла ошибка",
+ "modal.discard_changes": "У вас есть несохранённые изменения. Отменить их?",
+ "confirm.title": "Подтверждение",
+ "confirm.yes": "Да",
+ "confirm.no": "Нет",
+ "confirm.stop_all": "Остановить все запущенные цели?",
+ "confirm.turn_off_device": "Выключить это устройство?",
+ "common.loading": "Загрузка...",
+ "common.delete": "Удалить",
+ "common.edit": "Редактировать",
+ "common.clone": "Клонировать",
+ "common.none": "Нет",
+ "common.none_no_cspt": "Нет (без шаблона обработки)",
+ "common.none_no_input": "Нет (без источника)",
+ "common.none_own_speed": "Нет (своя скорость)",
+ "common.undo": "Отменить",
+ "validation.required": "Обязательное поле",
+ "bulk.processing": "Обработка…",
+ "api.error.timeout": "Превышено время ожидания — попробуйте снова",
+ "api.error.network": "Ошибка сети — проверьте подключение",
+ "palette.search": "Поиск…",
+ "section.filter.placeholder": "Фильтр...",
+ "section.filter.reset": "Очистить фильтр",
+ "tags.label": "Теги",
+ "tags.hint": "Назначьте теги для группировки и фильтрации карточек",
+ "tags.placeholder": "Добавить тег...",
+ "section.expand_all": "Развернуть все секции",
+ "section.collapse_all": "Свернуть все секции",
+ "streams.title": "Источники",
+ "streams.description": "Источники определяют конвейер захвата. Сырой источник захватывает экран с помощью шаблона захвата. Обработанный источник применяет постобработку к другому источнику. Назначайте источники устройствам.",
+ "streams.group.raw": "Источники",
+ "streams.group.raw_templates": "Шаблоны движка",
+ "streams.group.processed": "Источники",
+ "streams.group.proc_templates": "Шаблоны фильтров",
+ "streams.group.css_processing": "Шаблоны Обработки",
+ "streams.group.color_strip": "Цветовые Полосы",
+ "streams.group.audio": "Аудио",
+ "streams.group.audio_templates": "Аудио шаблоны",
+ "streams.section.streams": "Источники",
+ "streams.add": "Добавить Источник",
+ "streams.add.raw": "Добавить Захват Экрана",
+ "streams.add.processed": "Добавить Обработанный",
+ "streams.edit": "Редактировать Источник",
+ "streams.edit.raw": "Редактировать Захват Экрана",
+ "streams.edit.processed": "Редактировать Обработанный Источник",
+ "streams.name": "Имя Источника:",
+ "streams.name.placeholder": "Мой Источник",
+ "streams.type": "Тип:",
+ "streams.type.raw": "Захват экрана",
+ "streams.type.processed": "Обработанный",
+ "streams.display": "Дисплей:",
+ "streams.display.hint": "Какой экран захватывать",
+ "streams.capture_template": "Шаблон Движка:",
+ "streams.capture_template.hint": "Шаблон движка, определяющий способ захвата экрана",
+ "streams.target_fps": "Целевой FPS:",
+ "streams.target_fps.hint": "Целевое количество кадров в секунду (1-90)",
+ "streams.source": "Источник:",
+ "streams.source.hint": "Источник, к которому применяются фильтры обработки",
+ "streams.pp_template": "Шаблон Фильтра:",
+ "streams.pp_template.hint": "Шаблон фильтра для применения к источнику",
+ "streams.description_label": "Описание (необязательно):",
+ "streams.description_placeholder": "Опишите этот источник...",
+ "streams.created": "Источник успешно создан",
+ "streams.updated": "Источник успешно обновлён",
+ "streams.deleted": "Источник успешно удалён",
+ "streams.delete.confirm": "Вы уверены, что хотите удалить этот источник?",
+ "streams.modal.loading": "Загрузка...",
+ "streams.error.load": "Не удалось загрузить источники",
+ "streams.error.required": "Пожалуйста, заполните все обязательные поля",
+ "streams.error.delete": "Не удалось удалить источник",
+ "streams.test.title": "Тест Источника",
+ "streams.test.run": "Запустить",
+ "streams.test.running": "Тестирование источника...",
+ "streams.test.duration": "Длительность Захвата (с):",
+ "streams.test.error.failed": "Тест источника не удался",
+ "postprocessing.title": "Шаблоны Фильтров",
+ "postprocessing.description": "Шаблоны обработки определяют фильтры изображений и цветокоррекцию. Назначайте их обработанным источникам для единообразной постобработки на всех устройствах.",
+ "postprocessing.add": "Добавить Шаблон Фильтра",
+ "postprocessing.edit": "Редактировать Шаблон Фильтра",
+ "postprocessing.name": "Имя Шаблона:",
+ "postprocessing.name.placeholder": "Мой Шаблон Фильтра",
+ "filters.select_type": "Выберите тип фильтра...",
+ "filters.add": "Добавить фильтр",
+ "filters.remove": "Удалить",
+ "filters.drag_to_reorder": "Перетащите для изменения порядка",
+ "filters.empty": "Фильтры не добавлены. Используйте селектор ниже для добавления.",
+ "filters.brightness": "Яркость",
+ "filters.brightness.desc": "Регулировка общей яркости изображения",
+ "filters.saturation": "Насыщенность",
+ "filters.saturation.desc": "Усиление или снижение интенсивности цвета",
+ "filters.gamma": "Гамма",
+ "filters.gamma.desc": "Нелинейная коррекция кривой яркости",
+ "filters.downscaler": "Уменьшение",
+ "filters.downscaler.desc": "Снижение разрешения для быстрой обработки",
+ "filters.pixelate": "Пикселизация",
+ "filters.pixelate.desc": "Мозаичное усреднение блоков",
+ "filters.auto_crop": "Авто Обрезка",
+ "filters.auto_crop.desc": "Удаление чёрных полос из леттербокса",
+ "filters.flip": "Отражение",
+ "filters.flip.desc": "Зеркальное отражение по горизонтали или вертикали",
+ "filters.color_correction": "Цветокоррекция",
+ "filters.color_correction.desc": "Баланс белого и цветовая температура",
+ "filters.filter_template": "Шаблон фильтров",
+ "filters.filter_template.desc": "Встроить другой шаблон обработки",
+ "filters.css_filter_template": "Шаблон Фильтра Полос",
+ "filters.css_filter_template.desc": "Встроить другой шаблон обработки полос",
+ "filters.frame_interpolation": "Интерполяция кадров",
+ "filters.frame_interpolation.desc": "Сглаживание между кадрами",
+ "filters.noise_gate": "Шумоподавление",
+ "filters.noise_gate.desc": "Подавление малых изменений цвета ниже порога",
+ "filters.palette_quantization": "Квантизация палитры",
+ "filters.palette_quantization.desc": "Сокращение цветов до ограниченной палитры",
+ "filters.reverse": "Реверс",
+ "filters.reverse.desc": "Изменить порядок светодиодов на обратный",
+ "postprocessing.description_label": "Описание (необязательно):",
+ "postprocessing.description_placeholder": "Опишите этот шаблон...",
+ "postprocessing.created": "Шаблон успешно создан",
+ "postprocessing.updated": "Шаблон успешно обновлён",
+ "postprocessing.deleted": "Шаблон успешно удалён",
+ "postprocessing.delete.confirm": "Вы уверены, что хотите удалить этот шаблон фильтра?",
+ "postprocessing.error.load": "Не удалось загрузить шаблоны фильтров",
+ "postprocessing.error.required": "Пожалуйста, заполните все обязательные поля",
+ "postprocessing.error.delete": "Не удалось удалить шаблон фильтра",
+ "postprocessing.config.show": "Показать настройки",
+ "postprocessing.test.title": "Тест шаблона фильтра",
+ "postprocessing.test.source_stream": "Источник:",
+ "postprocessing.test.running": "Тестирование шаблона фильтра...",
+ "postprocessing.test.error.no_stream": "Пожалуйста, выберите источник",
+ "postprocessing.test.error.failed": "Тест шаблона фильтра не удался",
+ "css_processing.title": "Шаблоны Обработки Полос",
+ "css_processing.add": "Добавить Шаблон Обработки Полос",
+ "css_processing.edit": "Редактировать Шаблон Обработки Полос",
+ "css_processing.name": "Имя Шаблона:",
+ "css_processing.name_placeholder": "Мой Шаблон Обработки Полос",
+ "css_processing.description_label": "Описание (необязательно):",
+ "css_processing.description_placeholder": "Опишите этот шаблон...",
+ "css_processing.created": "Шаблон обработки полос создан",
+ "css_processing.updated": "Шаблон обработки полос обновлён",
+ "css_processing.deleted": "Шаблон обработки полос удалён",
+ "css_processing.delete.confirm": "Вы уверены, что хотите удалить этот шаблон обработки полос?",
+ "css_processing.error.required": "Заполните все обязательные поля",
+ "css_processing.error.load": "Ошибка загрузки шаблона обработки полос",
+ "css_processing.error.delete": "Ошибка удаления шаблона обработки полос",
+ "css_processing.error.clone_failed": "Не удалось клонировать шаблон обработки полос",
+ "device.button.stream_selector": "Настройки источника",
+ "device.stream_settings.title": "Настройки источника",
+ "device.stream_selector.label": "Источник:",
+ "device.stream_selector.hint": "Выберите источник, определяющий что это устройство захватывает и обрабатывает",
+ "device.stream_selector.none": "-- Источник не назначен --",
+ "device.stream_selector.saved": "Настройки источника обновлены",
+ "device.stream_settings.border_width": "Ширина границы (px):",
+ "device.stream_settings.border_width_hint": "Сколько пикселей от края экрана выбирать для цвета LED (1-100)",
+ "device.stream_settings.interpolation": "Режим интерполяции:",
+ "device.stream_settings.interpolation.average": "Среднее",
+ "device.stream_settings.interpolation.median": "Медиана",
+ "device.stream_settings.interpolation.dominant": "Доминантный",
+ "device.stream_settings.interpolation_hint": "Как вычислять цвет LED из выбранных пикселей",
+ "device.stream_settings.smoothing": "Сглаживание:",
+ "device.stream_settings.smoothing_hint": "Временное смешивание между кадрами (0=нет, 1=полное). Уменьшает мерцание.",
+ "device.tip.stream_selector": "Настройки источника и проекции LED для этого устройства",
+ "streams.group.static_image": "Статические",
+ "streams.add.static_image": "Добавить статическое изображение (источник)",
+ "streams.edit.static_image": "Редактировать статическое изображение (источник)",
+ "streams.type.static_image": "Статическое изображение",
+ "streams.group.video": "Видео",
+ "streams.add.video": "Добавить видеоисточник",
+ "streams.edit.video": "Редактировать видеоисточник",
+ "picture_source.type.video": "Видео",
+ "picture_source.type.video.desc": "Потоковые кадры из видеофайла, URL или YouTube",
+ "picture_source.video.url": "URL видео:",
+ "picture_source.video.url.hint": "Локальный файл, HTTP URL или YouTube URL",
+ "picture_source.video.url.placeholder": "https://example.com/video.mp4",
+ "picture_source.video.loop": "Зацикливание:",
+ "picture_source.video.speed": "Скорость воспроизведения:",
+ "picture_source.video.start_time": "Время начала (с):",
+ "picture_source.video.end_time": "Время окончания (с):",
+ "picture_source.video.resolution_limit": "Макс. ширина (px):",
+ "picture_source.video.resolution_limit.hint": "Уменьшение видео при декодировании для производительности",
+ "streams.image_source": "Источник изображения:",
+ "streams.image_source.placeholder": "https://example.com/image.jpg или C:\\path\\to\\image.png",
+ "streams.image_source.hint": "Введите URL (http/https) или локальный путь к изображению",
+ "streams.validate_image.validating": "Проверка...",
+ "streams.validate_image.valid": "Изображение доступно",
+ "streams.validate_image.invalid": "Изображение недоступно",
+ "targets.title": "Цели",
+ "targets.description": "Цели связывают источники цветовых полос с устройствами вывода. Каждая цель ссылается на устройство и источник цветовой полосы.",
+ "targets.subtab.wled": "LED",
+ "targets.subtab.led": "LED",
+ "targets.section.devices": "Устройства",
+ "targets.section.color_strips": "Источники цветовых полос",
+ "targets.section.targets": "Цели",
+ "targets.section.specific_settings": "Специальные настройки",
+ "targets.section.advanced": "Расширенные",
+ "targets.add": "Добавить Цель",
+ "targets.edit": "Редактировать Цель",
+ "targets.loading": "Загрузка целей...",
+ "targets.none": "Цели не настроены",
+ "targets.failed": "Не удалось загрузить цели",
+ "targets.name": "Имя Цели:",
+ "targets.name.placeholder": "Моя Цель",
+ "targets.device": "Устройство:",
+ "targets.device.hint": "Выберите LED устройство для передачи данных",
+ "targets.device.none": "-- Выберите устройство --",
+ "targets.color_strip_source": "Источник цветовой полосы:",
+ "targets.color_strip_source.hint": "Выберите источник цветовой полосы, который предоставляет цвета LED для этой цели",
+ "targets.no_css": "Нет источника",
+ "targets.source": "Источник:",
+ "targets.source.hint": "Какой источник изображения захватывать и обрабатывать",
+ "targets.source.none": "-- Источник не назначен --",
+ "targets.metrics.pipeline": "Детали конвейера",
+ "targets.fps": "Целевой FPS:",
+ "targets.fps.hint": "Целевая частота кадров для захвата и обновления LED (1-90)",
+ "targets.fps.rec": "Макс. аппаратный ≈ {fps} fps ({leds} LED)",
+ "targets.border_width": "Ширина границы (px):",
+ "targets.border_width.hint": "Сколько пикселей от края экрана выбирать для цвета LED (1-100)",
+ "targets.interpolation": "Режим интерполяции:",
+ "targets.interpolation.hint": "Как вычислять цвет LED из выбранных пикселей",
+ "targets.interpolation.average": "Среднее",
+ "targets.interpolation.median": "Медиана",
+ "targets.interpolation.dominant": "Доминантный",
+ "targets.smoothing": "Сглаживание:",
+ "targets.smoothing.hint": "Временное смешивание между кадрами (0=нет, 1=полное). Уменьшает мерцание.",
+ "targets.keepalive_interval": "Интервал поддержания связи:",
+ "targets.keepalive_interval.hint": "Как часто повторно отправлять последний кадр при статичном источнике для удержания устройства в режиме live (0.5-5.0с)",
+ "targets.created": "Цель успешно создана",
+ "targets.updated": "Цель успешно обновлена",
+ "targets.deleted": "Цель успешно удалена",
+ "targets.delete.confirm": "Вы уверены, что хотите удалить эту цель?",
+ "targets.error.load": "Не удалось загрузить цели",
+ "targets.error.required": "Пожалуйста, заполните все обязательные поля",
+ "targets.error.name_required": "Введите название цели",
+ "targets.error.delete": "Не удалось удалить цель",
+ "targets.button.start": "Запустить",
+ "targets.button.stop": "Остановить",
+ "targets.status.processing": "Обработка",
+ "targets.status.idle": "Ожидание",
+ "targets.status.error": "Ошибка",
+ "targets.metrics.actual_fps": "Факт. FPS",
+ "targets.metrics.target_fps": "Целев. FPS",
+ "targets.metrics.frames": "Кадры",
+ "targets.metrics.errors": "Ошибки",
+ "targets.subtab.key_colors": "Ключевые Цвета",
+ "targets.section.key_colors": "Цели Ключевых Цветов",
+ "kc.add": "Добавить Цель Ключевых Цветов",
+ "kc.edit": "Редактировать Цель Ключевых Цветов",
+ "kc.name": "Имя Цели:",
+ "kc.name.placeholder": "Моя Цель Ключевых Цветов",
+ "kc.source": "Источник:",
+ "kc.source.hint": "Из какого источника извлекать цвета",
+ "kc.source.none": "-- Источник не назначен --",
+ "kc.fps": "FPS Извлечения:",
+ "kc.fps.hint": "Сколько раз в секунду извлекать цвета (1-60)",
+ "kc.interpolation": "Режим Цвета:",
+ "kc.interpolation.hint": "Как вычислять ключевой цвет из пикселей в каждом прямоугольнике",
+ "kc.interpolation.average": "Среднее",
+ "kc.interpolation.median": "Медиана",
+ "kc.interpolation.dominant": "Доминантный",
+ "kc.interpolation.average.desc": "Среднее всех цветов пикселей",
+ "kc.interpolation.median.desc": "Медианное значение по каналам",
+ "kc.interpolation.dominant.desc": "Наиболее частый цвет",
+ "kc.smoothing": "Сглаживание:",
+ "kc.smoothing.hint": "Временное смешивание между извлечениями (0=нет, 1=полное)",
+ "kc.pattern_template": "Шаблон Паттерна:",
+ "kc.pattern_template.hint": "Выберите шаблон прямоугольников для извлечения цветов",
+ "kc.pattern_template.none": "-- Выберите шаблон паттерна --",
+ "kc.brightness_vs": "Источник Яркости:",
+ "kc.brightness_vs.hint": "Опциональный источник значений, динамически управляющий яркостью каждый кадр (умножается на ручной слайдер яркости)",
+ "kc.brightness_vs.none": "Нет (только ручная яркость)",
+ "kc.created": "Цель ключевых цветов успешно создана",
+ "kc.updated": "Цель ключевых цветов успешно обновлена",
+ "kc.deleted": "Цель ключевых цветов успешно удалена",
+ "kc.delete.confirm": "Вы уверены, что хотите удалить эту цель ключевых цветов?",
+ "kc.error.no_pattern": "Пожалуйста, выберите шаблон паттерна",
+ "kc.error.required": "Пожалуйста, заполните все обязательные поля",
+ "kc.colors.none": "Цвета пока не извлечены",
+ "kc.test": "Тест",
+ "kc.test.error": "Ошибка теста",
+ "targets.section.pattern_templates": "Шаблоны Паттернов",
+ "pattern.add": "Добавить Шаблон Паттерна",
+ "pattern.edit": "Редактировать Шаблон Паттерна",
+ "pattern.name": "Имя Шаблона:",
+ "pattern.name.placeholder": "Мой Шаблон Паттерна",
+ "pattern.description_label": "Описание (необязательно):",
+ "pattern.description_placeholder": "Опишите этот паттерн...",
+ "pattern.rectangles": "Прямоугольники",
+ "pattern.rect.name": "Имя",
+ "pattern.rect.x": "X",
+ "pattern.rect.y": "Y",
+ "pattern.rect.width": "Ш",
+ "pattern.rect.height": "В",
+ "pattern.rect.add": "Добавить Прямоугольник",
+ "pattern.rect.remove": "Удалить",
+ "pattern.rect.empty": "Прямоугольники не определены. Добавьте хотя бы один.",
+ "pattern.created": "Шаблон паттерна успешно создан",
+ "pattern.updated": "Шаблон паттерна успешно обновлён",
+ "pattern.deleted": "Шаблон паттерна успешно удалён",
+ "pattern.delete.confirm": "Вы уверены, что хотите удалить этот шаблон паттерна?",
+ "pattern.delete.referenced": "Невозможно удалить: шаблон используется целью",
+ "pattern.error.required": "Пожалуйста, заполните все обязательные поля",
+ "pattern.visual_editor": "Визуальный Редактор",
+ "pattern.capture_bg": "Захватить Фон",
+ "pattern.source_for_bg": "Источник для Фона:",
+ "pattern.source_for_bg.none": "-- Выберите источник --",
+ "pattern.delete_selected": "Удалить Выбранный",
+ "pattern.name.hint": "Описательное имя для этой раскладки прямоугольников",
+ "pattern.description.hint": "Необязательные заметки о назначении этого паттерна",
+ "pattern.visual_editor.hint": "Нажмите кнопки + чтобы добавить прямоугольники. Тяните края для изменения размера, тяните внутри для перемещения.",
+ "pattern.rectangles.hint": "Точная настройка позиций и размеров прямоугольников в координатах (0.0 до 1.0)",
+ "overlay.toggle": "Переключить наложение на экран",
+ "overlay.button.show": "Показать визуализацию наложения",
+ "overlay.button.hide": "Скрыть визуализацию наложения",
+ "overlay.started": "Визуализация наложения запущена",
+ "overlay.stopped": "Визуализация наложения остановлена",
+ "overlay.error.start": "Не удалось запустить наложение",
+ "overlay.error.stop": "Не удалось остановить наложение",
+ "dashboard.title": "Обзор",
+ "dashboard.section.targets": "Цели",
+ "dashboard.section.running": "Запущенные",
+ "dashboard.section.stopped": "Остановленные",
+ "dashboard.no_targets": "Нет настроенных целей",
+ "dashboard.uptime": "Время работы",
+ "dashboard.fps": "FPS",
+ "dashboard.errors": "Ошибки",
+ "dashboard.device": "Устройство",
+ "dashboard.stop_all": "Остановить все",
+ "dashboard.failed": "Не удалось загрузить обзор",
+ "dashboard.section.automations": "Автоматизации",
+ "dashboard.section.scenes": "Пресеты сцен",
+ "dashboard.section.sync_clocks": "Синхронные часы",
+ "dashboard.targets": "Цели",
+ "dashboard.section.performance": "Производительность системы",
+ "dashboard.perf.cpu": "ЦП",
+ "dashboard.perf.ram": "ОЗУ",
+ "dashboard.perf.gpu": "ГП",
+ "dashboard.perf.unavailable": "недоступно",
+ "dashboard.perf.color": "Цвет графика",
+ "dashboard.poll_interval": "Интервал обновления",
+ "automations.title": "Автоматизации",
+ "automations.empty": "Автоматизации не настроены. Создайте автоматизацию для автоматической активации сцен.",
+ "automations.add": "Добавить автоматизацию",
+ "automations.edit": "Редактировать автоматизацию",
+ "automations.delete.confirm": "Удалить автоматизацию \"{name}\"?",
+ "automations.name": "Название:",
+ "automations.name.hint": "Описательное имя для автоматизации",
+ "automations.name.placeholder": "Моя автоматизация",
+ "automations.enabled": "Включена:",
+ "automations.enabled.hint": "Отключённые автоматизации не активируются даже при выполнении условий",
+ "automations.condition_logic": "Логика условий:",
+ "automations.condition_logic.hint": "Как объединяются несколько условий: ЛЮБОЕ (ИЛИ) или ВСЕ (И)",
+ "automations.condition_logic.or": "Любое условие (ИЛИ)",
+ "automations.condition_logic.and": "Все условия (И)",
+ "automations.condition_logic.or.desc": "Срабатывает при любом совпадении",
+ "automations.condition_logic.and.desc": "Срабатывает только при всех",
+ "automations.conditions": "Условия:",
+ "automations.conditions.hint": "Правила, определяющие когда автоматизация активируется",
+ "automations.conditions.add": "Добавить условие",
+ "automations.conditions.empty": "Нет условий — автоматизация всегда активна когда включена",
+ "automations.condition.always": "Всегда",
+ "automations.condition.always.desc": "Всегда активно",
+ "automations.condition.always.hint": "Автоматизация активируется сразу при включении и остаётся активной.",
+ "automations.condition.startup": "Автозапуск",
+ "automations.condition.startup.desc": "При запуске сервера",
+ "automations.condition.startup.hint": "Активируется при запуске сервера и остаётся активной пока включена.",
+ "automations.condition.application": "Приложение",
+ "automations.condition.application.desc": "Приложение запущено",
+ "automations.condition.application.apps": "Приложения:",
+ "automations.condition.application.apps.hint": "Имена процессов, по одному на строку (например firefox.exe)",
+ "automations.condition.application.browse": "Обзор",
+ "automations.condition.application.search": "Фильтр процессов...",
+ "automations.condition.application.no_processes": "Процессы не найдены",
+ "automations.condition.application.match_type": "Тип соответствия:",
+ "automations.condition.application.match_type.hint": "Как определять наличие приложения",
+ "automations.condition.application.match_type.running": "Запущено",
+ "automations.condition.application.match_type.running.desc": "Процесс активен",
+ "automations.condition.application.match_type.topmost": "На переднем плане",
+ "automations.condition.application.match_type.topmost.desc": "Окно в фокусе",
+ "automations.condition.application.match_type.topmost_fullscreen": "Передний план + ПЭ",
+ "automations.condition.application.match_type.topmost_fullscreen.desc": "В фокусе + полный экран",
+ "automations.condition.application.match_type.fullscreen": "Полный экран",
+ "automations.condition.application.match_type.fullscreen.desc": "Любое полноэкранное",
+ "automations.condition.time_of_day": "Время суток",
+ "automations.condition.time_of_day.desc": "Диапазон времени",
+ "automations.condition.time_of_day.start_time": "Время начала:",
+ "automations.condition.time_of_day.end_time": "Время окончания:",
+ "automations.condition.time_of_day.overnight_hint": "Для ночных диапазонов (например 22:00–06:00) укажите время начала позже времени окончания.",
+ "automations.condition.system_idle": "Бездействие системы",
+ "automations.condition.system_idle.desc": "Бездействие/активность",
+ "automations.condition.system_idle.idle_minutes": "Тайм-аут бездействия (минуты):",
+ "automations.condition.system_idle.mode": "Режим срабатывания:",
+ "automations.condition.system_idle.when_idle": "При бездействии",
+ "automations.condition.system_idle.when_active": "При активности",
+ "automations.condition.display_state": "Состояние дисплея",
+ "automations.condition.display_state.desc": "Монитор вкл/выкл",
+ "automations.condition.display_state.state": "Состояние монитора:",
+ "automations.condition.display_state.on": "Включён",
+ "automations.condition.display_state.off": "Выключен (спящий режим)",
+ "automations.condition.mqtt": "MQTT",
+ "automations.condition.mqtt.desc": "MQTT сообщение",
+ "automations.condition.mqtt.topic": "Топик:",
+ "automations.condition.mqtt.payload": "Значение:",
+ "automations.condition.mqtt.match_mode": "Режим сравнения:",
+ "automations.condition.mqtt.match_mode.exact": "Точное совпадение",
+ "automations.condition.mqtt.match_mode.contains": "Содержит",
+ "automations.condition.mqtt.match_mode.regex": "Регулярное выражение",
+ "automations.condition.mqtt.hint": "Активировать при получении совпадающего значения по MQTT топику",
+ "automations.condition.webhook": "Вебхук",
+ "automations.condition.webhook.desc": "HTTP вызов",
+ "automations.condition.webhook.hint": "Активировать через HTTP-запрос от внешних сервисов (Home Assistant, IFTTT, curl и т.д.)",
+ "automations.condition.webhook.url": "URL вебхука:",
+ "automations.condition.webhook.copy": "Скопировать",
+ "automations.condition.webhook.copied": "Скопировано!",
+ "automations.condition.webhook.save_first": "Сначала сохраните автоматизацию для генерации URL вебхука",
+ "automations.scene": "Сцена:",
+ "automations.scene.hint": "Пресет сцены для активации при выполнении условий",
+ "automations.scene.search_placeholder": "Поиск сцен...",
+ "automations.scene.none_selected": "Нет (без сцены)",
+ "automations.scene.none_available": "Нет доступных сцен",
+ "automations.deactivation_mode": "Деактивация:",
+ "automations.deactivation_mode.hint": "Что происходит, когда условия перестают выполняться",
+ "automations.deactivation_mode.none": "Ничего",
+ "automations.deactivation_mode.none.desc": "Оставить текущее состояние",
+ "automations.deactivation_mode.revert": "Откатить",
+ "automations.deactivation_mode.revert.desc": "Вернуть предыдущее состояние",
+ "automations.deactivation_mode.fallback_scene": "Резервная",
+ "automations.deactivation_mode.fallback_scene.desc": "Активировать резервную сцену",
+ "automations.deactivation_scene": "Резервная сцена:",
+ "automations.deactivation_scene.hint": "Сцена для активации при деактивации автоматизации",
+ "automations.status.active": "Активна",
+ "automations.status.inactive": "Неактивна",
+ "automations.status.disabled": "Отключена",
+ "automations.action.disable": "Отключить",
+ "automations.last_activated": "Последняя активация",
+ "automations.logic.and": " И ",
+ "automations.logic.or": " ИЛИ ",
+ "automations.logic.all": "ВСЕ",
+ "automations.logic.any": "ЛЮБОЕ",
+ "automations.updated": "Автоматизация обновлена",
+ "automations.created": "Автоматизация создана",
+ "automations.deleted": "Автоматизация удалена",
+ "automations.error.name_required": "Введите название",
+ "automations.error.clone_failed": "Не удалось клонировать автоматизацию",
+ "scenes.title": "Сцены",
+ "scenes.add": "Захватить сцену",
+ "scenes.edit": "Редактировать сцену",
+ "scenes.name": "Название:",
+ "scenes.name.hint": "Описательное имя для этого пресета сцены",
+ "scenes.name.placeholder": "Моя сцена",
+ "scenes.description": "Описание:",
+ "scenes.description.hint": "Необязательное описание назначения этой сцены",
+ "scenes.targets": "Цели:",
+ "scenes.targets.hint": "Выберите какие цели включить в снимок сцены",
+ "scenes.targets.add": "Добавить цель",
+ "scenes.targets.search_placeholder": "Поиск целей...",
+ "scenes.capture": "Захват",
+ "scenes.activate": "Активировать сцену",
+ "scenes.recapture": "Перезахватить текущее состояние",
+ "scenes.delete": "Удалить сцену",
+ "scenes.targets_count": "целей",
+ "scenes.captured": "Сцена захвачена",
+ "scenes.updated": "Сцена обновлена",
+ "scenes.activated": "Сцена активирована",
+ "scenes.activated_partial": "Сцена активирована частично",
+ "scenes.errors": "ошибок",
+ "scenes.recaptured": "Сцена перезахвачена",
+ "scenes.deleted": "Сцена удалена",
+ "scenes.recapture_confirm": "Перезахватить текущее состояние в \"{name}\"?",
+ "scenes.delete_confirm": "Удалить сцену \"{name}\"?",
+ "scenes.error.name_required": "Необходимо указать название",
+ "scenes.error.save_failed": "Не удалось сохранить сцену",
+ "scenes.error.activate_failed": "Не удалось активировать сцену",
+ "scenes.error.recapture_failed": "Не удалось перезахватить сцену",
+ "scenes.error.delete_failed": "Не удалось удалить сцену",
+ "scenes.cloned": "Сцена клонирована",
+ "scenes.error.clone_failed": "Не удалось клонировать сцену",
+ "time.hours_minutes": "{h}ч {m}м",
+ "time.minutes_seconds": "{m}м {s}с",
+ "time.seconds": "{s}с",
+ "dashboard.type.led": "LED",
+ "dashboard.type.kc": "Цвета клавиш",
+ "aria.close": "Закрыть",
+ "aria.save": "Сохранить",
+ "aria.cancel": "Отмена",
+ "aria.previous": "Назад",
+ "aria.next": "Вперёд",
+ "aria.hint": "Показать подсказку",
+ "color_strip.select_type": "Выберите тип цветовой полосы",
+ "color_strip.add": "Добавить источник цветовой полосы",
+ "color_strip.edit": "Редактировать источник цветовой полосы",
+ "color_strip.name": "Название:",
+ "color_strip.name.placeholder": "Настенная полоса",
+ "color_strip.picture_source": "Источник изображения:",
+ "color_strip.picture_source.hint": "Источник захвата экрана для расчёта цветов светодиодов",
+ "color_strip.fps": "Целевой FPS:",
+ "color_strip.fps.hint": "Целевая частота кадров для обновления цветов светодиодов (10-90)",
+ "color_strip.interpolation": "Режим цвета:",
+ "color_strip.interpolation.hint": "Как вычислять цвет светодиода по пикселям рамки",
+ "color_strip.interpolation.average": "Среднее",
+ "color_strip.interpolation.median": "Медиана",
+ "color_strip.interpolation.dominant": "Доминирующий",
+ "color_strip.interpolation.average.desc": "Смешивает все пиксели в усреднённый цвет",
+ "color_strip.interpolation.median.desc": "Берёт средний цвет, игнорируя выбросы",
+ "color_strip.interpolation.dominant.desc": "Использует самый частый цвет в выборке",
+ "color_strip.smoothing": "Сглаживание:",
+ "color_strip.smoothing.hint": "Временное смешивание кадров (0=без смешивания, 1=полное). Уменьшает мерцание.",
+ "color_strip.frame_interpolation": "Интерполяция кадров:",
+ "color_strip.frame_interpolation.hint": "Смешивает последовательные захваченные кадры для вывода на полной целевой частоте кадров, даже если скорость захвата ниже. Уменьшает заметные ступеньки при плавных переходах.",
+ "color_strip.color_corrections": "Цветокоррекция",
+ "color_strip.brightness": "Яркость:",
+ "color_strip.brightness.hint": "Множитель яркости (0=выкл, 1=без изменений, 2=двойная). Применяется после извлечения цвета.",
+ "color_strip.saturation": "Насыщенность:",
+ "color_strip.saturation.hint": "Насыщенность цвета (0=оттенки серого, 1=без изменений, 2=двойная насыщенность)",
+ "color_strip.gamma": "Гамма:",
+ "color_strip.gamma.hint": "Гамма-коррекция (1=без коррекции, <1=ярче средние тона, >1=темнее средние тона)",
+ "color_strip.test_device": "Тестировать на устройстве:",
+ "color_strip.test_device.hint": "Выберите устройство для отправки тестовых пикселей при нажатии на рамку",
+ "color_strip.leds": "Количество светодиодов",
+ "color_strip.led_count": "Количество LED:",
+ "color_strip.led_count.hint": "Общее число светодиодов на физической полосе. Для источников экрана: 0 = автоматически из калибровки (светодиоды за ТВ будут чёрными). Для статического цвета: укажите точное количество светодиодов устройства.",
+ "color_strip.created": "Источник цветовой полосы создан",
+ "color_strip.updated": "Источник цветовой полосы обновлён",
+ "color_strip.deleted": "Источник цветовой полосы удалён",
+ "color_strip.delete.confirm": "Удалить этот источник цветовой полосы?",
+ "color_strip.delete.referenced": "Невозможно удалить: источник используется в цели",
+ "color_strip.error.name_required": "Введите название",
+ "color_strip.type": "Тип:",
+ "color_strip.type.hint": "Источник изображения получает цвета светодиодов из захвата экрана. Статический цвет заполняет все светодиоды одним постоянным цветом. Градиент распределяет цветовой градиент по всем светодиодам. Смена цвета плавно циклически переключается между заданными цветами. Композит накладывает несколько источников как смешанные слои. Аудиореактив управляет LED от аудиосигнала в реальном времени. API-ввод принимает массивы цветов LED от внешних клиентов через REST или WebSocket.",
+ "color_strip.type.picture": "Источник изображения",
+ "color_strip.type.picture.desc": "Цвета из захвата экрана",
+ "color_strip.type.picture_advanced": "Мультимонитор",
+ "color_strip.type.picture_advanced.desc": "Калибровка линиями по нескольким мониторам",
+ "color_strip.type.static": "Статический цвет",
+ "color_strip.type.static.desc": "Заливка одним цветом",
+ "color_strip.type.gradient": "Градиент",
+ "color_strip.type.gradient.desc": "Плавный переход цветов по ленте",
+ "color_strip.type.color_cycle": "Смена цвета",
+ "color_strip.type.color_cycle.desc": "Циклическая смена списка цветов",
+ "color_strip.static_color": "Цвет:",
+ "color_strip.static_color.hint": "Статический цвет, который будет отправлен на все светодиоды полосы.",
+ "color_strip.gradient.preview": "Градиент:",
+ "color_strip.gradient.preview.hint": "Предпросмотр градиента. Нажмите на дорожку маркеров чтобы добавить остановку. Перетащите маркеры для изменения позиции.",
+ "color_strip.gradient.stops": "Цветовые остановки:",
+ "color_strip.gradient.stops.hint": "Каждая остановка задаёт цвет в относительной позиции (0.0 = начало, 1.0 = конец). Кнопка ↔ добавляет цвет справа для создания резкого перехода.",
+ "color_strip.gradient.stops_count": "остановок",
+ "color_strip.gradient.add_stop": "+ Добавить",
+ "color_strip.gradient.position": "Позиция (0.0–1.0)",
+ "color_strip.gradient.bidir.hint": "Добавить второй цвет справа от этой остановки для создания резкого перехода в градиенте.",
+ "color_strip.gradient.min_stops": "Градиент должен содержать не менее 2 остановок",
+ "color_strip.gradient.preset": "Пресет:",
+ "color_strip.gradient.preset.hint": "Загрузить готовую палитру градиента. Выбор пресета заменяет текущие остановки.",
+ "color_strip.gradient.preset.custom": "— Свой —",
+ "color_strip.gradient.preset.rainbow": "Радуга",
+ "color_strip.gradient.preset.sunset": "Закат",
+ "color_strip.gradient.preset.ocean": "Океан",
+ "color_strip.gradient.preset.forest": "Лес",
+ "color_strip.gradient.preset.fire": "Огонь",
+ "color_strip.gradient.preset.lava": "Лава",
+ "color_strip.gradient.preset.aurora": "Аврора",
+ "color_strip.gradient.preset.ice": "Лёд",
+ "color_strip.gradient.preset.warm": "Тёплый",
+ "color_strip.gradient.preset.cool": "Холодный",
+ "color_strip.gradient.preset.neon": "Неон",
+ "color_strip.gradient.preset.pastel": "Пастельный",
+ "color_strip.gradient.preset.save_button": "Сохранить как пресет…",
+ "color_strip.gradient.preset.save_prompt": "Введите название пресета:",
+ "color_strip.gradient.preset.saved": "Пресет сохранён",
+ "color_strip.gradient.preset.deleted": "Пресет удалён",
+ "color_strip.gradient.preset.apply": "Применить",
+ "color_strip.animation": "Анимация",
+ "color_strip.animation.type": "Эффект:",
+ "color_strip.animation.type.hint": "Эффект анимации.",
+ "color_strip.animation.type.none": "Нет (без эффекта анимации)",
+ "color_strip.animation.type.none.desc": "Статичные цвета без анимации",
+ "color_strip.animation.type.breathing": "Дыхание",
+ "color_strip.animation.type.breathing.desc": "Плавное угасание и нарастание яркости",
+ "color_strip.animation.type.color_cycle": "Смена цвета",
+ "color_strip.animation.type.gradient_shift": "Сдвиг градиента",
+ "color_strip.animation.type.gradient_shift.desc": "Сдвигает градиент вдоль ленты",
+ "color_strip.animation.type.wave": "Волна",
+ "color_strip.animation.type.wave.desc": "Синусоидальная волна яркости вдоль ленты",
+ "color_strip.animation.type.strobe": "Стробоскоп",
+ "color_strip.animation.type.strobe.desc": "Быстрое мигание вкл/выкл",
+ "color_strip.animation.type.sparkle": "Искры",
+ "color_strip.animation.type.sparkle.desc": "Случайные светодиоды кратковременно вспыхивают",
+ "color_strip.animation.type.pulse": "Пульс",
+ "color_strip.animation.type.pulse.desc": "Резкая вспышка яркости с быстрым затуханием",
+ "color_strip.animation.type.candle": "Свеча",
+ "color_strip.animation.type.candle.desc": "Тёплое мерцание, как у свечи",
+ "color_strip.animation.type.rainbow_fade": "Радужный перелив",
+ "color_strip.animation.type.rainbow_fade.desc": "Циклический переход по всему спектру оттенков",
+ "color_strip.animation.speed": "Скорость:",
+ "color_strip.animation.speed.hint": "Множитель скорости анимации. 1.0 ≈ один цикл в секунду для дыхания; большие значения ускоряют анимацию.",
+ "color_strip.color_cycle.colors": "Цвета:",
+ "color_strip.color_cycle.colors.hint": "Список цветов для плавной циклической смены. Минимум 2 цвета. По умолчанию — полный радужный спектр.",
+ "color_strip.color_cycle.add_color": "+ Добавить цвет",
+ "color_strip.color_cycle.speed": "Скорость:",
+ "color_strip.color_cycle.speed.hint": "Множитель скорости смены. 1.0 ≈ один полный цикл за 20 секунд; большие значения ускоряют смену.",
+ "color_strip.color_cycle.min_colors": "Смена цвета должна содержать не менее 2 цветов",
+ "color_strip.type.effect": "Эффект",
+ "color_strip.type.effect.desc": "Процедурные эффекты: огонь, плазма, аврора",
+ "color_strip.type.effect.hint": "Процедурные LED-эффекты (огонь, метеор, плазма, шум, аврора), генерируемые в реальном времени.",
+ "color_strip.type.composite": "Композит",
+ "color_strip.type.composite.desc": "Наложение и смешивание источников",
+ "color_strip.type.composite.hint": "Наложение нескольких источников цветовой ленты как слоёв с режимами смешивания и прозрачностью.",
+ "color_strip.type.mapped": "Маппинг",
+ "color_strip.type.mapped.desc": "Назначение источников на зоны LED",
+ "color_strip.type.mapped.hint": "Назначает разные источники цветовой полосы на разные диапазоны LED (зоны). В отличие от композита, маппинг размещает источники рядом друг с другом.",
+ "color_strip.type.audio": "Аудиореактив",
+ "color_strip.type.audio.desc": "LED от аудиосигнала",
+ "color_strip.type.audio.hint": "Цвета LED управляются аудиосигналом в реальном времени — системный звук или микрофон.",
+ "color_strip.type.api_input": "API-ввод",
+ "color_strip.type.api_input.desc": "Приём цветов от внешних приложений",
+ "color_strip.type.api_input.hint": "Принимает массивы цветов LED от внешних клиентов через REST POST или WebSocket. Используйте для интеграции с собственным ПО, домашней автоматизацией или любой системой, способной отправлять HTTP-запросы.",
+ "color_strip.api_input.fallback_color": "Цвет по умолчанию:",
+ "color_strip.api_input.fallback_color.hint": "Цвет для отображения, когда данные не получены в течение периода ожидания. LED покажут этот цвет при запуске и после потери соединения.",
+ "color_strip.api_input.timeout": "Тайм-аут (секунды):",
+ "color_strip.api_input.timeout.hint": "Время ожидания новых данных о цветах перед возвратом к цвету по умолчанию. Установите 0, чтобы не использовать тайм-аут.",
+ "color_strip.api_input.endpoints": "Эндпоинты для отправки:",
+ "color_strip.api_input.endpoints.hint": "Используйте эти URL для отправки данных о цветах LED из вашего внешнего приложения. REST принимает JSON, WebSocket принимает как JSON, так и бинарные кадры.",
+ "color_strip.api_input.save_first": "Сначала сохраните источник, чтобы увидеть URL эндпоинтов.",
+ "color_strip.type.notification": "Уведомления",
+ "color_strip.type.notification.desc": "Разовый эффект по вебхуку",
+ "color_strip.type.notification.hint": "Вспышка, пульс или волна при срабатывании через вебхук. Предназначен для использования как слой в композитном источнике.",
+ "color_strip.notification.effect": "Эффект:",
+ "color_strip.notification.effect.hint": "Визуальный эффект при уведомлении. Вспышка — линейное затухание, Пульс — плавная волна, Волна — заполнение и затухание.",
+ "color_strip.notification.effect.flash": "Вспышка",
+ "color_strip.notification.effect.flash.desc": "Мгновенное включение, линейное затухание",
+ "color_strip.notification.effect.pulse": "Пульс",
+ "color_strip.notification.effect.pulse.desc": "Плавное свечение колоколом",
+ "color_strip.notification.effect.sweep": "Волна",
+ "color_strip.notification.effect.sweep.desc": "Заполняет слева направо, затем гаснет",
+ "color_strip.notification.duration": "Длительность (мс):",
+ "color_strip.notification.duration.hint": "Как долго длится эффект уведомления в миллисекундах.",
+ "color_strip.notification.default_color": "Цвет по умолчанию:",
+ "color_strip.notification.default_color.hint": "Цвет, когда для приложения нет специфического назначения цвета.",
+ "color_strip.notification.filter_mode": "Фильтр приложений:",
+ "color_strip.notification.filter_mode.hint": "Фильтр уведомлений по имени приложения. Выкл = все, Белый список = только указанные, Чёрный список = все кроме указанных.",
+ "color_strip.notification.filter_mode.off": "Выкл",
+ "color_strip.notification.filter_mode.whitelist": "Белый список",
+ "color_strip.notification.filter_mode.blacklist": "Чёрный список",
+ "color_strip.notification.filter_mode.off.desc": "Принимать все уведомления",
+ "color_strip.notification.filter_mode.whitelist.desc": "Только указанные приложения",
+ "color_strip.notification.filter_mode.blacklist.desc": "Все кроме указанных приложений",
+ "color_strip.notification.filter_list": "Список приложений:",
+ "color_strip.notification.filter_list.hint": "Одно имя приложения на строку. Используйте «Обзор» для выбора из запущенных процессов.",
+ "color_strip.notification.filter_list.placeholder": "Discord\nSlack\nTelegram",
+ "color_strip.notification.app_colors": "Цвета приложений",
+ "color_strip.notification.app_colors.label": "Назначения цветов:",
+ "color_strip.notification.app_colors.hint": "Индивидуальные цвета для приложений. Каждая строка связывает имя приложения с цветом уведомления.",
+ "color_strip.notification.app_colors.add": "+ Добавить",
+ "color_strip.notification.endpoint": "Вебхук:",
+ "color_strip.notification.endpoint.hint": "URL для запуска уведомлений из внешних систем. POST с JSON телом: {\"app\": \"AppName\", \"color\": \"#FF0000\"}.",
+ "color_strip.notification.save_first": "Сначала сохраните источник, чтобы увидеть URL вебхука.",
+ "color_strip.notification.app_count": "прилож.",
+ "color_strip.notification.test": "Тестовое уведомление",
+ "color_strip.notification.test.ok": "Уведомление отправлено",
+ "color_strip.notification.test.no_streams": "Нет запущенных потоков для этого источника",
+ "color_strip.notification.test.error": "Не удалось отправить уведомление",
+ "color_strip.notification.history.title": "История уведомлений",
+ "color_strip.notification.history.hint": "Последние ОС-уведомления, захваченные слушателем (новейшие сверху). До 50 записей.",
+ "color_strip.notification.history.empty": "Уведомления ещё не захвачены",
+ "color_strip.notification.history.unavailable": "Слушатель уведомлений ОС недоступен на этой платформе",
+ "color_strip.notification.history.error": "Не удалось загрузить историю уведомлений",
+ "color_strip.notification.history.refresh": "Обновить",
+ "color_strip.notification.history.unknown_app": "Неизвестное приложение",
+ "color_strip.notification.history.fired": "Потоков запущено",
+ "color_strip.notification.history.filtered": "Потоков отфильтровано",
+ "color_strip.test.title": "Предпросмотр",
+ "color_strip.test.connecting": "Подключение...",
+ "color_strip.test.error": "Не удалось подключиться к потоку предпросмотра",
+ "color_strip.test.led_count": "Кол-во LED:",
+ "color_strip.test.fps": "FPS:",
+ "color_strip.test.receive_fps": "Частота приёма",
+ "color_strip.test.apply": "Применить",
+ "color_strip.test.composite": "Композит",
+ "color_strip.preview.title": "Предпросмотр",
+ "color_strip.preview.not_connected": "Не подключено",
+ "color_strip.preview.connecting": "Подключение...",
+ "color_strip.preview.connected": "Подключено",
+ "color_strip.preview.unsupported": "Предпросмотр недоступен для этого типа источника",
+ "color_strip.type.daylight": "Дневной цикл",
+ "color_strip.type.daylight.desc": "Имитация естественного дневного света за 24 часа",
+ "color_strip.type.daylight.hint": "Имитирует цветовую температуру солнца в течение суток — от тёплого рассвета до прохладного дневного света, заката и ночи.",
+ "color_strip.daylight.speed": "Скорость:",
+ "color_strip.daylight.speed.hint": "Множитель скорости цикла. 1.0 = полный цикл день/ночь за ~4 минуты.",
+ "color_strip.daylight.use_real_time": "Реальное время:",
+ "color_strip.daylight.use_real_time.hint": "Если включено, цвет LED соответствует реальному времени суток. Настройка скорости игнорируется.",
+ "color_strip.daylight.real_time": "Реальное время",
+ "color_strip.daylight.latitude": "Широта:",
+ "color_strip.daylight.latitude.hint": "Географическая широта (-90 до 90). Влияет на время восхода/заката в режиме реального времени.",
+ "color_strip.type.candlelight": "Свечи",
+ "color_strip.type.candlelight.desc": "Реалистичная имитация мерцания свечей",
+ "color_strip.type.candlelight.hint": "Реалистичное мерцание свечей с тёплыми тонами и органическими паттернами.",
+ "color_strip.candlelight.color": "Базовый цвет:",
+ "color_strip.candlelight.color.hint": "Тёплый базовый цвет пламени свечи. По умолчанию — натуральный тёплый янтарь.",
+ "color_strip.candlelight.intensity": "Интенсивность мерцания:",
+ "color_strip.candlelight.intensity.hint": "Сила мерцания свечей. Низкие значения — мягкое свечение, высокие — свеча на ветру.",
+ "color_strip.candlelight.num_candles_label": "Количество свечей:",
+ "color_strip.candlelight.num_candles": "свечей",
+ "color_strip.candlelight.num_candles.hint": "Сколько независимых источников свечей вдоль ленты. Каждый мерцает по-своему.",
+ "color_strip.candlelight.speed": "Скорость мерцания:",
+ "color_strip.candlelight.speed.hint": "Скорость анимации мерцания. Большие значения — более быстрое, беспокойное пламя.",
+ "color_strip.type.processed": "Обработанный",
+ "color_strip.type.processed.desc": "Применить шаблон обработки к другому источнику",
+ "color_strip.type.processed.hint": "Оборачивает существующий источник цветовой полосы и пропускает его вывод через цепочку фильтров.",
+ "color_strip.processed.input": "Источник:",
+ "color_strip.processed.input.hint": "Источник цветовой полосы, вывод которого будет обработан",
+ "color_strip.processed.template": "Шаблон обработки:",
+ "color_strip.processed.template.hint": "Цепочка фильтров для применения к выводу входного источника",
+ "color_strip.processed.error.no_input": "Выберите входной источник",
+ "color_strip.composite.layers": "Слои:",
+ "color_strip.composite.layers.hint": "Наложение нескольких источников. Первый слой — нижний, последний — верхний. Каждый слой может иметь свой режим смешивания и прозрачность.",
+ "color_strip.composite.add_layer": "+ Добавить слой",
+ "color_strip.composite.source": "Источник",
+ "color_strip.composite.blend_mode": "Смешивание",
+ "color_strip.composite.blend_mode.normal": "Обычное",
+ "color_strip.composite.blend_mode.normal.desc": "Стандартное альфа-смешивание",
+ "color_strip.composite.blend_mode.add": "Сложение",
+ "color_strip.composite.blend_mode.add.desc": "Осветляет, складывая цвета",
+ "color_strip.composite.blend_mode.multiply": "Умножение",
+ "color_strip.composite.blend_mode.multiply.desc": "Затемняет, умножая цвета",
+ "color_strip.composite.blend_mode.screen": "Экран",
+ "color_strip.composite.blend_mode.screen.desc": "Осветляет, обратное умножение",
+ "color_strip.composite.blend_mode.override": "Замена",
+ "color_strip.composite.blend_mode.override.desc": "Чёрный = прозрачный, яркий = непрозрачный",
+ "color_strip.composite.opacity": "Непрозрачность",
+ "color_strip.composite.brightness": "Яркость",
+ "color_strip.composite.brightness.none": "Нет (полная яркость)",
+ "color_strip.composite.processing": "Обработка",
+ "color_strip.composite.enabled": "Включён",
+ "color_strip.composite.error.min_layers": "Необходим хотя бы 1 слой",
+ "color_strip.composite.error.no_source": "Для каждого слоя должен быть выбран источник",
+ "color_strip.composite.layers_count": "слоёв",
+ "color_strip.mapped.zones": "Зоны:",
+ "color_strip.mapped.zones.hint": "Каждая зона привязывает источник цветовой полосы к определённому диапазону LED. Зоны размещаются рядом — промежутки остаются чёрными.",
+ "color_strip.mapped.add_zone": "+ Добавить зону",
+ "color_strip.mapped.zone_source": "Источник",
+ "color_strip.mapped.zone_start": "Начало LED",
+ "color_strip.mapped.zone_end": "Конец LED",
+ "color_strip.mapped.zone_reverse": "Реверс",
+ "color_strip.mapped.zones_count": "зон",
+ "color_strip.mapped.select_source": "Поиск источников...",
+ "color_strip.mapped.error.no_source": "Для каждой зоны должен быть выбран источник",
+ "color_strip.audio.visualization": "Визуализация:",
+ "color_strip.audio.visualization.hint": "Способ отображения аудиоданных на LED.",
+ "color_strip.audio.viz.spectrum": "Анализатор спектра",
+ "color_strip.audio.viz.spectrum.desc": "Частотные полосы по ленте",
+ "color_strip.audio.viz.beat_pulse": "Пульс бита",
+ "color_strip.audio.viz.beat_pulse.desc": "Все LED пульсируют в такт",
+ "color_strip.audio.viz.vu_meter": "VU-метр",
+ "color_strip.audio.viz.vu_meter.desc": "Уровень громкости заполняет ленту",
+ "color_strip.audio.source": "Аудиоисточник:",
+ "color_strip.audio.source.hint": "Аудиоисточник для визуализации. Может быть многоканальным (устройство) или моно (один канал). Создавайте и управляйте аудиоисточниками на вкладке Источники.",
+ "color_strip.audio.sensitivity": "Чувствительность:",
+ "color_strip.audio.sensitivity.hint": "Множитель усиления аудиосигнала. Более высокие значения делают LED чувствительнее к тихим звукам.",
+ "color_strip.audio.smoothing": "Сглаживание:",
+ "color_strip.audio.smoothing.hint": "Временное сглаживание между кадрами. Более высокие значения дают плавную, но медленнее реагирующую визуализацию.",
+ "color_strip.audio.palette": "Палитра:",
+ "color_strip.audio.palette.hint": "Цветовая палитра для полос спектра или пульсации бита.",
+ "color_strip.audio.color": "Базовый цвет:",
+ "color_strip.audio.color.hint": "Цвет низкого уровня для полосы VU-метра.",
+ "color_strip.audio.color_peak": "Пиковый цвет:",
+ "color_strip.audio.color_peak.hint": "Цвет высокого уровня в верхней части полосы VU-метра.",
+ "color_strip.audio.mirror": "Зеркало:",
+ "color_strip.audio.mirror.hint": "Зеркалирование спектра от центра к краям: басы в середине, высокие частоты по краям.",
+ "color_strip.effect.type": "Тип эффекта:",
+ "color_strip.effect.type.hint": "Выберите процедурный алгоритм.",
+ "color_strip.effect.fire": "Огонь",
+ "color_strip.effect.fire.desc": "Клеточный автомат, имитирующий поднимающееся пламя с диффузией тепла",
+ "color_strip.effect.meteor": "Метеор",
+ "color_strip.effect.meteor.desc": "Яркая точка движется по ленте с экспоненциально затухающим хвостом",
+ "color_strip.effect.plasma": "Плазма",
+ "color_strip.effect.plasma.desc": "Наложение синусоидальных волн с палитрой — классический демо-эффект",
+ "color_strip.effect.noise": "Шум",
+ "color_strip.effect.noise.desc": "Прокручиваемый фрактальный шум, отображённый на палитру",
+ "color_strip.effect.aurora": "Аврора",
+ "color_strip.effect.aurora.desc": "Наложенные шумовые полосы, дрейфующие и смешивающиеся — в стиле северного сияния",
+ "color_strip.effect.speed": "Скорость:",
+ "color_strip.effect.speed.hint": "Множитель скорости анимации эффекта (0.1 = очень медленно, 10.0 = очень быстро).",
+ "color_strip.effect.palette": "Палитра:",
+ "color_strip.effect.palette.hint": "Цветовая палитра для отображения значений эффекта в RGB-цвета.",
+ "color_strip.effect.color": "Цвет метеора:",
+ "color_strip.effect.color.hint": "Цвет головной точки метеора.",
+ "color_strip.effect.intensity": "Интенсивность:",
+ "color_strip.effect.intensity.hint": "Интенсивность эффекта — частота искр (огонь), затухание хвоста (метеор) или диапазон яркости (аврора).",
+ "color_strip.effect.scale": "Масштаб:",
+ "color_strip.effect.scale.hint": "Пространственный масштаб — частота волн (плазма), уровень масштабирования (шум) или ширина полос (аврора).",
+ "color_strip.effect.mirror": "Отражение:",
+ "color_strip.effect.mirror.hint": "Режим отскока — метеор меняет направление у краёв ленты вместо переноса.",
+ "color_strip.palette.fire": "Огонь",
+ "color_strip.palette.ocean": "Океан",
+ "color_strip.palette.lava": "Лава",
+ "color_strip.palette.forest": "Лес",
+ "color_strip.palette.rainbow": "Радуга",
+ "color_strip.palette.aurora": "Аврора",
+ "color_strip.palette.sunset": "Закат",
+ "color_strip.palette.ice": "Лёд",
+ "audio_source.title": "Аудиоисточники",
+ "audio_source.group.multichannel": "Многоканальные",
+ "audio_source.group.mono": "Моно",
+ "audio_source.add": "Добавить аудиоисточник",
+ "audio_source.add.multichannel": "Добавить многоканальный",
+ "audio_source.add.mono": "Добавить моно",
+ "audio_source.edit": "Редактировать аудиоисточник",
+ "audio_source.edit.multichannel": "Редактировать многоканальный",
+ "audio_source.edit.mono": "Редактировать моно",
+ "audio_source.name": "Название:",
+ "audio_source.name.placeholder": "Системный звук",
+ "audio_source.name.hint": "Описательное имя для этого аудиоисточника",
+ "audio_source.type": "Тип:",
+ "audio_source.type.hint": "Многоканальный захватывает все каналы с аудиоустройства. Моно извлекает один канал из многоканального источника.",
+ "audio_source.type.multichannel": "Многоканальный",
+ "audio_source.type.mono": "Моно",
+ "audio_source.device": "Аудиоустройство:",
+ "audio_source.device.hint": "Источник аудиосигнала. Устройства обратной петли захватывают системный звук; устройства ввода — микрофон или линейный вход.",
+ "audio_source.refresh_devices": "Обновить устройства",
+ "audio_source.parent": "Родительский источник:",
+ "audio_source.parent.hint": "Многоканальный источник для извлечения канала",
+ "audio_source.channel": "Канал:",
+ "audio_source.channel.hint": "Какой аудиоканал извлечь из многоканального источника",
+ "audio_source.channel.mono": "Моно (Л+П микс)",
+ "audio_source.channel.left": "Левый",
+ "audio_source.channel.right": "Правый",
+ "audio_source.description": "Описание (необязательно):",
+ "audio_source.description.placeholder": "Опишите этот аудиоисточник...",
+ "audio_source.description.hint": "Необязательные заметки об этом аудиоисточнике",
+ "audio_source.created": "Аудиоисточник создан",
+ "audio_source.updated": "Аудиоисточник обновлён",
+ "audio_source.deleted": "Аудиоисточник удалён",
+ "audio_source.delete.confirm": "Удалить этот аудиоисточник?",
+ "audio_source.error.name_required": "Введите название",
+ "audio_source.audio_template": "Аудиошаблон:",
+ "audio_source.audio_template.hint": "Шаблон аудиозахвата определяет, какой движок и настройки использовать для этого устройства",
+ "audio_source.test": "Тест",
+ "audio_source.test.title": "Тест аудиоисточника",
+ "audio_source.test.rms": "RMS",
+ "audio_source.test.peak": "Пик",
+ "audio_source.test.beat": "Бит",
+ "audio_source.test.connecting": "Подключение...",
+ "audio_source.test.error": "Ошибка теста аудио",
+ "audio_template.test": "Тест",
+ "audio_template.test.title": "Тест аудиошаблона",
+ "audio_template.test.device": "Аудиоустройство:",
+ "audio_template.test.device.hint": "Выберите устройство для захвата звука во время теста",
+ "audio_template.test.run": "Запуск",
+ "audio_template.title": "Аудиошаблоны",
+ "audio_template.add": "Добавить аудиошаблон",
+ "audio_template.edit": "Редактировать аудиошаблон",
+ "audio_template.name": "Название шаблона:",
+ "audio_template.name.placeholder": "Мой аудиошаблон",
+ "audio_template.description.label": "Описание (необязательно):",
+ "audio_template.description.placeholder": "Опишите этот шаблон...",
+ "audio_template.engine": "Аудиодвижок:",
+ "audio_template.engine.hint": "Выберите движок аудиозахвата. WASAPI — только Windows с поддержкой loopback. Sounddevice — кроссплатформенный.",
+ "audio_template.engine.unavailable": "Недоступен",
+ "audio_template.engine.unavailable.hint": "Этот движок недоступен в вашей системе",
+ "audio_template.config": "Конфигурация",
+ "audio_template.config.show": "Показать конфигурацию",
+ "audio_template.created": "Аудиошаблон создан",
+ "audio_template.updated": "Аудиошаблон обновлён",
+ "audio_template.deleted": "Аудиошаблон удалён",
+ "audio_template.delete.confirm": "Удалить этот аудиошаблон?",
+ "audio_template.error.load": "Не удалось загрузить аудиошаблоны",
+ "audio_template.error.engines": "Не удалось загрузить аудиодвижки",
+ "audio_template.error.required": "Пожалуйста, заполните все обязательные поля",
+ "audio_template.error.delete": "Не удалось удалить аудиошаблон",
+ "streams.group.value": "Источники значений",
+ "streams.group.sync": "Часы синхронизации",
+ "tree.group.picture": "Источники изображений",
+ "tree.group.capture": "Захват экрана",
+ "tree.group.static": "Статичные",
+ "tree.group.processing": "Обработанные",
+ "tree.group.strip": "Цветовые полосы",
+ "tree.group.audio": "Аудио",
+ "tree.group.utility": "Утилиты",
+ "tree.leaf.sources": "Источники",
+ "tree.leaf.engine_templates": "Шаблоны движка",
+ "tree.leaf.images": "Изображения",
+ "tree.leaf.video": "Видео",
+ "tree.leaf.filter_templates": "Шаблоны фильтров",
+ "tree.leaf.processing_templates": "Шаблоны обработки",
+ "tree.leaf.templates": "Шаблоны",
+ "value_source.group.title": "Источники значений",
+ "value_source.select_type": "Выберите тип источника значений",
+ "value_source.add": "Добавить источник значений",
+ "value_source.edit": "Редактировать источник значений",
+ "value_source.name": "Название:",
+ "value_source.name.placeholder": "Пульс яркости",
+ "value_source.name.hint": "Описательное имя для этого источника значений",
+ "value_source.type": "Тип:",
+ "value_source.type.hint": "Статический выдаёт постоянное значение. Анимированный циклически меняет форму волны. Аудио реагирует на звук. Адаптивные типы автоматически подстраивают яркость по времени суток или содержимому сцены.",
+ "value_source.type.static": "Статический",
+ "value_source.type.static.desc": "Постоянное выходное значение",
+ "value_source.type.animated": "Анимированный",
+ "value_source.type.animated.desc": "Циклическая смена по форме волны",
+ "value_source.type.audio": "Аудио",
+ "value_source.type.audio.desc": "Реагирует на звуковой сигнал",
+ "value_source.type.adaptive_time": "Адаптивный (Время)",
+ "value_source.type.adaptive_time.desc": "Подстройка по времени суток",
+ "value_source.type.adaptive_scene": "Адаптивный (Сцена)",
+ "value_source.type.adaptive_scene.desc": "Подстройка по содержимому сцены",
+ "value_source.type.daylight": "Дневной цикл",
+ "value_source.type.daylight.desc": "Яркость следует за циклом дня/ночи",
+ "value_source.daylight.speed": "Скорость:",
+ "value_source.daylight.speed.hint": "Множитель скорости цикла. 1.0 = полный цикл день/ночь за ~4 минуты.",
+ "value_source.daylight.use_real_time": "Реальное время:",
+ "value_source.daylight.use_real_time.hint": "Яркость следует за реальным временем суток. Скорость игнорируется.",
+ "value_source.daylight.enable_real_time": "Следовать за часами",
+ "value_source.daylight.latitude": "Широта:",
+ "value_source.daylight.latitude.hint": "Географическая широта (-90 до 90). Влияет на время восхода/заката в режиме реального времени.",
+ "value_source.daylight.real_time": "Реальное время",
+ "value_source.daylight.speed_label": "Скорость",
+ "value_source.value": "Значение:",
+ "value_source.value.hint": "Постоянное выходное значение (0.0 = выкл, 1.0 = полная яркость)",
+ "value_source.waveform": "Форма волны:",
+ "value_source.waveform.hint": "Форма цикла анимации яркости",
+ "value_source.waveform.sine": "Синус",
+ "value_source.waveform.triangle": "Треугольник",
+ "value_source.waveform.square": "Прямоугольник",
+ "value_source.waveform.sawtooth": "Пила",
+ "value_source.speed": "Скорость (цикл/мин):",
+ "value_source.speed.hint": "Циклов в минуту — как быстро повторяется волна (1 = очень медленно, 120 = очень быстро)",
+ "value_source.min_value": "Мин. значение:",
+ "value_source.min_value.hint": "Минимальный выход цикла волны",
+ "value_source.max_value": "Макс. значение:",
+ "value_source.max_value.hint": "Максимальный выход цикла волны",
+ "value_source.audio_source": "Аудиоисточник:",
+ "value_source.audio_source.hint": "Аудиоисточник для считывания уровня звука (многоканальный или моно)",
+ "value_source.mode": "Режим:",
+ "value_source.mode.hint": "RMS измеряет среднюю громкость. Пик отслеживает самые громкие моменты. Бит реагирует на ритм.",
+ "value_source.mode.rms": "RMS (Громкость)",
+ "value_source.mode.peak": "Пик",
+ "value_source.mode.beat": "Бит",
+ "value_source.mode.rms.desc": "Средний уровень громкости",
+ "value_source.mode.peak.desc": "Отслеживание пиковых моментов",
+ "value_source.mode.beat.desc": "Детекция ритмических ударов",
+ "value_source.auto_gain": "Авто-усиление:",
+ "value_source.auto_gain.hint": "Автоматически нормализует уровни звука, чтобы выходное значение использовало полный диапазон независимо от громкости входного сигнала",
+ "value_source.auto_gain.enable": "Включить авто-усиление",
+ "value_source.sensitivity": "Чувствительность:",
+ "value_source.sensitivity.hint": "Множитель усиления аудиосигнала (выше = более реактивный)",
+ "value_source.scene_sensitivity.hint": "Множитель усиления сигнала яркости (выше = более чувствительный к изменениям яркости)",
+ "value_source.smoothing": "Сглаживание:",
+ "value_source.smoothing.hint": "Временное сглаживание (0 = мгновенный отклик, 1 = очень плавный/медленный)",
+ "value_source.audio_min_value": "Мин. значение:",
+ "value_source.audio_min_value.hint": "Выход при тишине (напр. 0.3 = минимум 30% яркости)",
+ "value_source.audio_max_value": "Макс. значение:",
+ "value_source.audio_max_value.hint": "Выход при максимальном уровне звука",
+ "value_source.schedule": "Расписание:",
+ "value_source.schedule.hint": "Определите минимум 2 временные точки. Яркость линейно интерполируется между ними, с переходом через полночь.",
+ "value_source.schedule.add": "+ Добавить точку",
+ "value_source.schedule.points": "точек",
+ "value_source.picture_source": "Источник изображения:",
+ "value_source.picture_source.hint": "Источник изображения, кадры которого будут анализироваться на среднюю яркость.",
+ "value_source.scene_behavior": "Поведение:",
+ "value_source.scene_behavior.hint": "Дополнение: тёмная сцена = высокая яркость (для фоновой подсветки). Совпадение: яркая сцена = высокая яркость.",
+ "value_source.scene_behavior.complement": "Дополнение (тёмный → ярко)",
+ "value_source.scene_behavior.match": "Совпадение (яркий → ярко)",
+ "value_source.adaptive_min_value": "Мин. значение:",
+ "value_source.adaptive_min_value.hint": "Минимальная выходная яркость",
+ "value_source.adaptive_max_value": "Макс. значение:",
+ "value_source.adaptive_max_value.hint": "Максимальная выходная яркость",
+ "value_source.error.schedule_min": "Расписание требует минимум 2 временные точки",
+ "value_source.description": "Описание (необязательно):",
+ "value_source.description.placeholder": "Опишите этот источник значений...",
+ "value_source.description.hint": "Необязательные заметки об этом источнике значений",
+ "value_source.created": "Источник значений создан",
+ "value_source.updated": "Источник значений обновлён",
+ "value_source.deleted": "Источник значений удалён",
+ "value_source.delete.confirm": "Удалить этот источник значений?",
+ "value_source.error.name_required": "Введите название",
+ "value_source.test": "Тест",
+ "value_source.test.title": "Тест источника значений",
+ "value_source.test.connecting": "Подключение...",
+ "value_source.test.error": "Не удалось подключиться",
+ "value_source.test.current": "Текущее",
+ "value_source.test.min": "Мин",
+ "value_source.test.max": "Макс",
+ "test.frames": "Кадры",
+ "test.fps": "Кадр/с",
+ "test.avg_capture": "Сред",
+ "targets.brightness_vs": "Источник яркости:",
+ "targets.brightness_vs.hint": "Необязательный источник значений для динамического управления яркостью каждый кадр (переопределяет яркость устройства)",
+ "targets.brightness_vs.none": "Нет (яркость устройства)",
+ "targets.min_brightness_threshold": "Мин. порог яркости:",
+ "targets.min_brightness_threshold.hint": "Если итоговая яркость (яркость пикселей × яркость устройства/источника) ниже этого значения, светодиоды полностью выключаются (0 = отключено)",
+ "targets.adaptive_fps": "Адаптивный FPS:",
+ "targets.adaptive_fps.hint": "Автоматически снижает частоту отправки, когда устройство перестаёт отвечать, и постепенно восстанавливает её при стабилизации. Рекомендуется для WiFi-устройств со слабым сигналом.",
+ "targets.protocol": "Протокол:",
+ "targets.protocol.hint": "DDP отправляет пиксели по быстрому UDP (рекомендуется). HTTP использует JSON API — медленнее, но надёжнее, ограничение ~500 LED.",
+ "targets.protocol.ddp": "DDP (UDP)",
+ "targets.protocol.ddp.desc": "Быстрые UDP-пакеты — рекомендуется",
+ "targets.protocol.http": "HTTP",
+ "targets.protocol.http.desc": "JSON API — медленнее, ≤500 LED",
+ "targets.protocol.serial": "Serial",
+ "search.open": "Поиск (Ctrl+K)",
+ "search.placeholder": "Поиск... (Ctrl+K)",
+ "search.loading": "Загрузка...",
+ "search.no_results": "Ничего не найдено",
+ "search.group.devices": "Устройства",
+ "search.group.targets": "LED-цели",
+ "search.group.kc_targets": "Цели Key Colors",
+ "search.group.css": "Источники цветных лент",
+ "search.group.automations": "Автоматизации",
+ "search.group.streams": "Потоки изображений",
+ "search.group.capture_templates": "Шаблоны захвата",
+ "search.group.pp_templates": "Шаблоны постобработки",
+ "search.group.pattern_templates": "Шаблоны паттернов",
+ "search.group.audio": "Аудиоисточники",
+ "search.group.value": "Источники значений",
+ "search.group.scenes": "Пресеты сцен",
+ "search.group.cspt": "Шаблоны обработки полос",
+ "search.group.sync_clocks": "Синхронные часы",
+ "search.group.actions": "Действия",
+ "search.action.start": "Запустить",
+ "search.action.stop": "Остановить",
+ "search.action.activate": "Активировать",
+ "search.action.enable": "Включить",
+ "search.action.disable": "Отключить",
+ "settings.backup.label": "Резервное копирование",
+ "settings.backup.hint": "Скачать всю конфигурацию (устройства, цели, потоки, шаблоны, автоматизации) в виде одного JSON-файла.",
+ "settings.backup.button": "Скачать резервную копию",
+ "settings.backup.success": "Резервная копия скачана",
+ "settings.backup.error": "Ошибка скачивания резервной копии",
+ "settings.restore.label": "Восстановление конфигурации",
+ "settings.restore.hint": "Загрузите ранее сохранённый файл резервной копии для замены всей конфигурации. Сервер перезапустится автоматически.",
+ "settings.restore.button": "Восстановить из копии",
+ "settings.restore.confirm": "Это заменит ВСЮ конфигурацию и перезапустит сервер. Вы уверены?",
+ "settings.restore.success": "Конфигурация восстановлена",
+ "settings.restore.error": "Ошибка восстановления",
+ "settings.restore.restarting": "Сервер перезапускается...",
+ "settings.restore.restart_timeout": "Сервер не отвечает. Обновите страницу вручную.",
+ "settings.restart_server": "Перезапустить сервер",
+ "settings.restart_confirm": "Перезапустить сервер? Активные цели будут остановлены.",
+ "settings.restarting": "Перезапуск сервера...",
+ "settings.button.close": "Закрыть",
+ "settings.log_level.label": "Уровень логирования",
+ "settings.log_level.hint": "Изменить подробность логов сервера в реальном времени. DEBUG — максимум деталей, CRITICAL — только критические ошибки.",
+ "settings.log_level.save": "Применить",
+ "settings.log_level.saved": "Уровень логирования изменён",
+ "settings.log_level.save_error": "Не удалось изменить уровень логирования",
+ "settings.log_level.desc.debug": "Подробный вывод для разработки",
+ "settings.log_level.desc.info": "Обычные сообщения",
+ "settings.log_level.desc.warning": "Возможные проблемы",
+ "settings.log_level.desc.error": "Только ошибки",
+ "settings.log_level.desc.critical": "Только критические ошибки",
+ "settings.auto_backup.label": "Авто-бэкап",
+ "settings.auto_backup.hint": "Автоматическое создание периодических резервных копий конфигурации. Старые копии удаляются при превышении максимального количества.",
+ "settings.auto_backup.enable": "Включить авто-бэкап",
+ "settings.auto_backup.interval_label": "Интервал",
+ "settings.auto_backup.max_label": "Макс. копий",
+ "settings.auto_backup.save": "Сохранить настройки",
+ "settings.auto_backup.saved": "Настройки авто-бэкапа сохранены",
+ "settings.auto_backup.save_error": "Не удалось сохранить настройки авто-бэкапа",
+ "settings.auto_backup.last_backup": "Последний бэкап",
+ "settings.auto_backup.never": "Никогда",
+ "settings.saved_backups.label": "Сохранённые копии",
+ "settings.saved_backups.hint": "Файлы авто-бэкапа на сервере. Скачайте для локального хранения или удалите для освобождения места.",
+ "settings.saved_backups.empty": "Нет сохранённых копий",
+ "settings.saved_backups.restore": "Восстановить",
+ "settings.saved_backups.download": "Скачать",
+ "settings.saved_backups.delete": "Удалить",
+ "settings.saved_backups.delete_confirm": "Удалить эту резервную копию?",
+ "settings.saved_backups.delete_error": "Не удалось удалить копию",
+ "settings.saved_backups.type.auto": "авто",
+ "settings.saved_backups.type.manual": "ручной",
+ "settings.mqtt.label": "MQTT",
+ "settings.mqtt.hint": "Настройте подключение к MQTT-брокеру для условий и триггеров автоматизации.",
+ "settings.mqtt.enabled": "Включить MQTT",
+ "settings.mqtt.host_label": "Хост брокера",
+ "settings.mqtt.port_label": "Порт",
+ "settings.mqtt.username_label": "Имя пользователя",
+ "settings.mqtt.password_label": "Пароль",
+ "settings.mqtt.password_set_hint": "Пароль задан — оставьте пустым, чтобы сохранить",
+ "settings.mqtt.client_id_label": "Идентификатор клиента",
+ "settings.mqtt.base_topic_label": "Базовый топик",
+ "settings.mqtt.save": "Сохранить настройки MQTT",
+ "settings.mqtt.saved": "Настройки MQTT сохранены",
+ "settings.mqtt.save_error": "Не удалось сохранить настройки MQTT",
+ "settings.mqtt.error_host_required": "Требуется указать хост брокера",
+ "settings.logs.label": "Журнал сервера",
+ "settings.logs.hint": "Просмотр журнала сервера в реальном времени. Используйте фильтр для отображения нужных уровней.",
+ "settings.logs.connect": "Подключить",
+ "settings.logs.disconnect": "Отключить",
+ "settings.logs.clear": "Очистить",
+ "settings.logs.error": "Ошибка подключения к журналу",
+ "settings.logs.filter.all": "Все уровни",
+ "settings.logs.filter.info": "Info+",
+ "settings.logs.filter.warning": "Warning+",
+ "settings.logs.filter.error": "Только ошибки",
+ "settings.logs.filter.all_desc": "Все сообщения лога",
+ "settings.logs.filter.info_desc": "Info, предупреждения и ошибки",
+ "settings.logs.filter.warning_desc": "Только предупреждения и ошибки",
+ "settings.logs.filter.error_desc": "Только ошибки",
+ "device.error.power_off_failed": "Не удалось выключить устройство",
+ "device.error.remove_failed": "Не удалось удалить устройство",
+ "device.error.settings_load_failed": "Не удалось загрузить настройки устройства",
+ "device.error.brightness": "Не удалось обновить яркость",
+ "device.error.required": "Пожалуйста, заполните все поля",
+ "device.error.update": "Не удалось обновить устройство",
+ "device.error.save": "Не удалось сохранить настройки",
+ "device.error.clone_failed": "Не удалось клонировать устройство",
+ "device_discovery.error.fill_all_fields": "Пожалуйста, заполните все поля",
+ "device_discovery.added": "Устройство успешно добавлено",
+ "device_discovery.error.add_failed": "Не удалось добавить устройство",
+ "calibration.error.load_failed": "Не удалось загрузить калибровку",
+ "calibration.error.css_load_failed": "Не удалось загрузить источник цветовой полосы",
+ "calibration.error.test_toggle_failed": "Не удалось переключить тестовый край",
+ "calibration.error.save_failed": "Не удалось сохранить калибровку",
+ "calibration.error.led_count_mismatch": "Общее количество LED должно совпадать с количеством LED устройства",
+ "calibration.error.led_count_exceeded": "Калиброванных LED больше, чем общее количество LED",
+ "calibration.mode.simple": "Простой",
+ "calibration.mode.advanced": "Расширенный",
+ "calibration.switch_to_advanced": "Расширенный режим",
+ "calibration.advanced.title": "Расширенная калибровка",
+ "calibration.advanced.switch_to_simple": "Простой режим",
+ "calibration.advanced.lines_title": "Линии",
+ "calibration.advanced.canvas_hint": "Перетаскивайте мониторы. Нажимайте на грани для выбора линий. Прокрутка — масштаб, перетаскивание пустого места — сдвиг.",
+ "calibration.advanced.reset_view": "Сбросить вид",
+ "calibration.advanced.line_properties": "Свойства линии",
+ "calibration.advanced.picture_source": "Источник:",
+ "calibration.advanced.picture_source.hint": "Источник изображения (монитор), с которого эта линия снимает данные",
+ "calibration.advanced.edge": "Грань:",
+ "calibration.advanced.edge.hint": "С какой грани экрана снимать пиксели",
+ "calibration.advanced.led_count": "Светодиоды:",
+ "calibration.advanced.led_count.hint": "Количество светодиодов на этой линии",
+ "calibration.advanced.span_start": "Начало:",
+ "calibration.advanced.span_start.hint": "Откуда начинается захват вдоль грани (0 = начало, 1 = конец). Позволяет покрыть только часть грани.",
+ "calibration.advanced.span_end": "Конец:",
+ "calibration.advanced.span_end.hint": "Где заканчивается захват вдоль грани (0 = начало, 1 = конец). Вместе с «Начало» определяет активный участок.",
+ "calibration.advanced.border_width": "Глубина (пкс):",
+ "calibration.advanced.border_width.hint": "Сколько пикселей вглубь от края захватывать. Большие значения берут больше внутренней части экрана.",
+ "calibration.advanced.reverse": "Реверс",
+ "calibration.advanced.no_lines_warning": "Добавьте хотя бы одну линию",
+ "dashboard.error.automation_toggle_failed": "Не удалось переключить автоматизацию",
+ "dashboard.error.start_failed": "Не удалось запустить обработку",
+ "dashboard.error.stop_failed": "Не удалось остановить обработку",
+ "dashboard.error.stop_all": "Не удалось остановить все цели",
+ "target.error.editor_open_failed": "Не удалось открыть редактор цели",
+ "target.error.start_failed": "Не удалось запустить цель",
+ "target.error.stop_failed": "Не удалось остановить цель",
+ "target.error.clone_failed": "Не удалось клонировать цель",
+ "target.error.delete_failed": "Не удалось удалить цель",
+ "targets.stop_all.button": "Остановить все",
+ "targets.stop_all.none_running": "Нет запущенных целей",
+ "targets.stop_all.stopped": "Остановлено целей: {count}",
+ "targets.stop_all.error": "Не удалось остановить цели",
+ "audio_source.error.load": "Не удалось загрузить аудиоисточник",
+ "audio_template.error.clone_failed": "Не удалось клонировать аудиошаблон",
+ "value_source.error.load": "Не удалось загрузить источник значений",
+ "color_strip.error.editor_open_failed": "Не удалось открыть редактор цветовой полосы",
+ "color_strip.error.clone_failed": "Не удалось клонировать источник цветовой полосы",
+ "color_strip.error.delete_failed": "Не удалось удалить источник цветовой полосы",
+ "pattern.error.editor_open_failed": "Не удалось открыть редактор шаблона узоров",
+ "pattern.error.clone_failed": "Не удалось клонировать шаблон узоров",
+ "pattern.error.delete_failed": "Не удалось удалить шаблон узоров",
+ "pattern.error.capture_bg_failed": "Не удалось захватить фон",
+ "stream.error.clone_picture_failed": "Не удалось клонировать источник изображения",
+ "stream.error.clone_capture_failed": "Не удалось клонировать шаблон захвата",
+ "stream.error.clone_pp_failed": "Не удалось клонировать шаблон постобработки",
+ "kc_target.error.editor_open_failed": "Не удалось открыть редактор ключевых цветов",
+ "kc_target.error.clone_failed": "Не удалось клонировать цель ключевых цветов",
+ "kc_target.error.delete_failed": "Не удалось удалить цель ключевых цветов",
+ "theme.switched.dark": "Переключено на тёмную тему",
+ "theme.switched.light": "Переключено на светлую тему",
+ "accent.color.updated": "Цвет акцента обновлён",
+ "search.footer": "↑↓ навигация · Enter выбор · Esc закрыть",
+ "sync_clock.group.title": "Часы синхронизации",
+ "sync_clock.add": "Добавить часы",
+ "sync_clock.edit": "Редактировать часы",
+ "sync_clock.name": "Название:",
+ "sync_clock.name.placeholder": "Основные часы анимации",
+ "sync_clock.name.hint": "Описательное название для этих часов синхронизации",
+ "sync_clock.speed": "Скорость:",
+ "sync_clock.speed.hint": "Множитель скорости анимации для всех привязанных источников. 1.0 = обычная, 2.0 = двойная, 0.5 = половинная.",
+ "sync_clock.description": "Описание (необязательно):",
+ "sync_clock.description.placeholder": "Необязательное описание",
+ "sync_clock.description.hint": "Необязательные заметки о назначении этих часов",
+ "sync_clock.status.running": "Работает",
+ "sync_clock.status.paused": "Приостановлено",
+ "sync_clock.action.pause": "Приостановить",
+ "sync_clock.action.resume": "Возобновить",
+ "sync_clock.action.reset": "Сбросить",
+ "sync_clock.error.name_required": "Название часов обязательно",
+ "sync_clock.error.load": "Не удалось загрузить часы синхронизации",
+ "sync_clock.created": "Часы синхронизации созданы",
+ "sync_clock.updated": "Часы синхронизации обновлены",
+ "sync_clock.deleted": "Часы синхронизации удалены",
+ "sync_clock.paused": "Часы приостановлены",
+ "sync_clock.resumed": "Часы возобновлены",
+ "sync_clock.reset_done": "Часы сброшены на ноль",
+ "sync_clock.delete.confirm": "Удалить эти часы синхронизации? Привязанные источники потеряют синхронизацию и будут работать на скорости по умолчанию.",
+ "sync_clock.elapsed": "Прошло времени",
+ "color_strip.clock": "Часы синхронизации:",
+ "color_strip.clock.hint": "Привязка к часам для синхронизации анимации между источниками. Скорость управляется на часах.",
+ "graph.title": "Граф",
+ "graph.fit_all": "Показать все узлы",
+ "graph.zoom_in": "Приблизить",
+ "graph.zoom_out": "Отдалить",
+ "graph.search": "Поиск узлов",
+ "graph.search_placeholder": "Поиск сущностей...",
+ "graph.legend": "Легенда",
+ "graph.minimap": "Миникарта",
+ "graph.relayout": "Перестроить",
+ "graph.empty": "Ещё нет сущностей",
+ "graph.empty.hint": "Создайте устройства, источники и цели, чтобы увидеть их здесь.",
+ "graph.disconnect": "Отключить",
+ "graph.connection_updated": "Соединение обновлено",
+ "graph.connection_failed": "Не удалось обновить соединение",
+ "graph.connection_removed": "Соединение удалено",
+ "graph.disconnect_failed": "Не удалось отключить",
+ "graph.relayout_confirm": "Сбросить все ручные позиции узлов и перестроить граф?",
+ "graph.fullscreen": "Полноэкранный режим",
+ "graph.add_entity": "Добавить сущность",
+ "graph.color_picker": "Цвет узла",
+ "graph.filter": "Фильтр узлов",
+ "graph.filter_placeholder": "Фильтр по имени...",
+ "graph.filter_clear": "Очистить фильтр",
+ "graph.filter_running": "Запущен",
+ "graph.filter_stopped": "Остановлен",
+ "graph.filter_types": "Типы",
+ "graph.filter_group.capture": "Захват",
+ "graph.filter_group.strip": "Цвет. полосы",
+ "graph.filter_group.audio": "Аудио",
+ "graph.filter_group.targets": "Цели",
+ "graph.filter_group.other": "Другое",
+ "graph.bulk_delete_confirm": "Удалить {count} выбранных сущностей?",
+ "graph.nothing_to_undo": "Нечего отменять",
+ "graph.nothing_to_redo": "Нечего повторять",
+ "graph.help_title": "Горячие клавиши",
+ "graph.help.search": "Поиск",
+ "graph.help.filter": "Фильтр",
+ "graph.help.add": "Добавить сущность",
+ "graph.help.shortcuts": "Горячие клавиши",
+ "graph.help.delete": "Удалить / Отсоединить",
+ "graph.help.select_all": "Выбрать все",
+ "graph.help.undo": "Отменить",
+ "graph.help.redo": "Повторить",
+ "graph.help.fullscreen": "Полный экран",
+ "graph.help.deselect": "Снять выбор",
+ "graph.help.navigate": "Навигация по узлам",
+ "graph.help.click": "Клик",
+ "graph.help.click_desc": "Выбрать узел",
+ "graph.help.dblclick": "Двойной клик",
+ "graph.help.dblclick_desc": "Приблизить к узлу",
+ "graph.help.shift_click": "Shift+Клик",
+ "graph.help.shift_click_desc": "Множественный выбор",
+ "graph.help.shift_drag": "Shift+Перетащить",
+ "graph.help.shift_drag_desc": "Выбор рамкой",
+ "graph.help.drag_node": "Перетащить узел",
+ "graph.help.drag_node_desc": "Переместить",
+ "graph.help.drag_port": "Перетащить порт",
+ "graph.help.drag_port_desc": "Соединить сущности",
+ "graph.help.right_click": "ПКМ по связи",
+ "graph.help.right_click_desc": "Отсоединить связь",
+ "graph.tooltip.fps": "FPS",
+ "graph.tooltip.errors": "Ошибки",
+ "graph.tooltip.uptime": "Время работы",
+ "automation.enabled": "Автоматизация включена",
+ "automation.disabled": "Автоматизация выключена",
+ "scene_preset.activated": "Пресет активирован",
+ "scene_preset.used_by": "Используется в %d автоматизации(ях)",
+ "settings.api_keys.label": "API-ключи",
+ "settings.api_keys.hint": "API-ключи определяются в конфигурационном файле сервера (config.yaml). Отредактируйте файл и перезапустите сервер для применения изменений.",
+ "settings.api_keys.empty": "API-ключи не настроены",
+ "settings.api_keys.load_error": "Не удалось загрузить API-ключи",
+ "settings.partial.label": "Частичный экспорт / импорт",
+ "settings.partial.hint": "Экспортировать или импортировать один тип объектов. Импорт заменяет или объединяет данные и перезапускает сервер.",
+ "settings.partial.store.devices": "Устройства",
+ "settings.partial.store.output_targets": "LED-цели",
+ "settings.partial.store.color_strip_sources": "Цветные полосы",
+ "settings.partial.store.picture_sources": "Источники изображений",
+ "settings.partial.store.audio_sources": "Аудио-источники",
+ "settings.partial.store.audio_templates": "Аудио-шаблоны",
+ "settings.partial.store.capture_templates": "Шаблоны захвата",
+ "settings.partial.store.postprocessing_templates": "Шаблоны постобработки",
+ "settings.partial.store.color_strip_processing_templates": "Шаблоны обработки полос",
+ "settings.partial.store.pattern_templates": "Шаблоны паттернов",
+ "settings.partial.store.value_sources": "Источники значений",
+ "settings.partial.store.sync_clocks": "Синхронные часы",
+ "settings.partial.store.automations": "Автоматизации",
+ "settings.partial.store.scene_presets": "Пресеты сцен",
+ "settings.partial.export_button": "Экспорт",
+ "settings.partial.import_button": "Импорт из файла",
+ "settings.partial.merge_label": "Объединить (добавить/перезаписать, сохранить существующие)",
+ "settings.partial.export_success": "Экспорт выполнен",
+ "settings.partial.export_error": "Ошибка экспорта",
+ "settings.partial.import_success": "Импорт выполнен",
+ "settings.partial.import_error": "Ошибка импорта",
+ "settings.partial.import_confirm_replace": "Это ЗАМЕНИТ все данные {store} и перезапустит сервер. Продолжить?",
+ "settings.partial.import_confirm_merge": "Это ОБЪЕДИНИТ данные {store} и перезапустит сервер. Продолжить?",
+ "section.empty.devices": "Устройств пока нет. Нажмите + для добавления.",
+ "section.empty.targets": "LED-целей пока нет. Нажмите + для добавления.",
+ "section.empty.kc_targets": "Целей ключевых цветов пока нет. Нажмите + для добавления.",
+ "section.empty.pattern_templates": "Шаблонов паттернов пока нет. Нажмите + для добавления.",
+ "section.empty.picture_sources": "Источников пока нет. Нажмите + для добавления.",
+ "section.empty.capture_templates": "Шаблонов захвата пока нет. Нажмите + для добавления.",
+ "section.empty.pp_templates": "Шаблонов постобработки пока нет. Нажмите + для добавления.",
+ "section.empty.audio_sources": "Аудио-источников пока нет. Нажмите + для добавления.",
+ "section.empty.audio_templates": "Аудио-шаблонов пока нет. Нажмите + для добавления.",
+ "section.empty.color_strips": "Цветных полос пока нет. Нажмите + для добавления.",
+ "section.empty.value_sources": "Источников значений пока нет. Нажмите + для добавления.",
+ "section.empty.sync_clocks": "Синхронных часов пока нет. Нажмите + для добавления.",
+ "section.empty.cspt": "Шаблонов обработки полос пока нет. Нажмите + для добавления.",
+ "section.empty.automations": "Автоматизаций пока нет. Нажмите + для добавления.",
+ "section.empty.scenes": "Пресетов сцен пока нет. Нажмите + для добавления.",
+ "bulk.select": "Выбрать",
+ "bulk.cancel": "Отмена",
+ "bulk.selected_count.one": "{count} выбран",
+ "bulk.selected_count.few": "{count} выбрано",
+ "bulk.selected_count.many": "{count} выбрано",
+ "bulk.select_all": "Выбрать все",
+ "bulk.deselect_all": "Снять выбор",
+ "bulk.delete": "Удалить",
+ "bulk.start": "Запустить",
+ "bulk.stop": "Остановить",
+ "bulk.enable": "Включить",
+ "bulk.disable": "Выключить",
+ "bulk.confirm_delete.one": "Удалить {count} элемент?",
+ "bulk.confirm_delete.few": "Удалить {count} элемента?",
+ "bulk.confirm_delete.many": "Удалить {count} элементов?",
+ "color_strip": {
+ "notification": {
+ "search_apps": "Поиск приложений…"
+ }
+ }
+}
\ No newline at end of file
diff --git a/server/src/wled_controller/static/locales/zh.json b/server/src/wled_controller/static/locales/zh.json
index 2a16750..998aa07 100644
--- a/server/src/wled_controller/static/locales/zh.json
+++ b/server/src/wled_controller/static/locales/zh.json
@@ -1,1747 +1,1748 @@
{
- "app.title": "LED Grab",
- "app.version": "版本:",
- "app.api_docs": "API 文档",
- "app.connection_lost": "服务器不可达",
- "app.connection_retrying": "正在尝试重新连接…",
- "demo.badge": "演示",
- "demo.banner": "您正处于演示模式 — 所有设备和数据均为虚拟。未使用任何真实硬件。",
- "theme.toggle": "切换主题",
- "bg.anim.toggle": "切换动态背景",
- "accent.title": "主题色",
- "accent.custom": "自定义",
- "accent.reset": "重置",
- "locale.change": "切换语言",
- "auth.login": "登录",
- "auth.logout": "退出",
- "auth.authenticated": "● 已认证",
- "auth.title": "登录 LED Grab",
- "auth.message": "请输入 API 密钥以进行身份验证并访问 LED Grab。",
- "auth.label": "API 密钥:",
- "auth.placeholder": "输入您的 API 密钥...",
- "auth.hint": "API 密钥将安全存储在浏览器的本地存储中。",
- "auth.button.cancel": "取消",
- "auth.button.login": "登录",
- "auth.error.required": "请输入 API 密钥",
- "auth.success": "登录成功!",
- "auth.logout.confirm": "确定要退出登录吗?",
- "auth.logout.success": "已成功退出",
- "auth.please_login": "请先登录",
- "auth.session_expired": "会话已过期或 API 密钥无效,请重新登录。",
- "auth.toggle_password": "切换密码可见性",
- "auth.prompt_enter": "Enter your API key:",
- "auth.prompt_update": "Current API key is set. Enter new key to update or leave blank to remove:",
- "api_key.login": "登录",
- "displays.title": "可用显示器",
- "displays.layout": "显示器",
- "displays.information": "显示器信息",
- "displays.legend.primary": "主显示器",
- "displays.legend.secondary": "副显示器",
- "displays.badge.primary": "主",
- "displays.badge.secondary": "副",
- "displays.resolution": "分辨率:",
- "displays.refresh_rate": "刷新率:",
- "displays.position": "位置:",
- "displays.index": "显示器序号:",
- "displays.loading": "正在加载显示器...",
- "displays.none": "没有可用的显示器",
- "displays.failed": "加载显示器失败",
- "displays.picker.title": "选择显示器",
- "displays.picker.title.device": "选择设备",
- "displays.picker.select": "选择显示器...",
- "displays.picker.click_to_select": "点击选择此显示器",
- "displays.picker.adb_connect": "连接 ADB 设备",
- "displays.picker.adb_connect.placeholder": "IP 地址(例如 192.168.2.201)",
- "displays.picker.adb_connect.button": "连接",
- "displays.picker.adb_connect.success": "设备已连接",
- "displays.picker.adb_connect.error": "连接设备失败",
- "displays.picker.adb_disconnect": "断开连接",
- "displays.picker.no_android": "未找到 Android 设备。请通过 USB 连接或在上方输入 IP 地址。",
- "templates.title": "引擎模板",
- "templates.description": "采集模板定义屏幕的采集方式。每个模板使用特定的采集引擎(MSS、DXcam、WGC)及自定义设置。将模板分配给设备以获得最佳性能。",
- "templates.loading": "正在加载模板...",
- "templates.empty": "尚未配置采集模板",
- "templates.add": "添加引擎模板",
- "templates.edit": "编辑引擎模板",
- "templates.name": "模板名称:",
- "templates.name.placeholder": "我的自定义模板",
- "templates.description.label": "描述(可选):",
- "templates.description.placeholder": "描述此模板...",
- "templates.engine": "采集引擎:",
- "templates.engine.hint": "选择要使用的屏幕采集技术",
- "templates.engine.select": "选择引擎...",
- "templates.engine.unavailable": "不可用",
- "templates.engine.unavailable.hint": "此引擎在您的系统上不可用",
- "templates.engine.mss.desc": "跨平台,纯Python",
- "templates.engine.dxcam.desc": "DirectX,低延迟",
- "templates.engine.bettercam.desc": "DirectX,高性能",
- "templates.engine.camera.desc": "USB/IP摄像头捕获",
- "templates.engine.scrcpy.desc": "Android屏幕镜像",
- "templates.engine.wgc.desc": "Windows图形捕获",
- "templates.config": "配置",
- "templates.config.show": "显示配置",
- "templates.config.none": "无额外配置",
- "templates.config.default": "默认",
- "templates.config.camera_backend.auto": "自动检测最佳后端",
- "templates.config.camera_backend.dshow": "Windows DirectShow",
- "templates.config.camera_backend.msmf": "Windows Media Foundation",
- "templates.config.camera_backend.v4l2": "Linux Video4Linux2",
- "templates.created": "模板创建成功",
- "templates.updated": "模板更新成功",
- "templates.deleted": "模板删除成功",
- "templates.delete.confirm": "确定要删除此模板吗?",
- "templates.error.load": "加载模板失败",
- "templates.error.engines": "加载引擎失败",
- "templates.error.required": "请填写所有必填项",
- "templates.error.delete": "删除模板失败",
- "templates.test.title": "测试采集",
- "templates.test.description": "保存前测试此模板,查看采集预览和性能指标。",
- "templates.test.display": "显示器:",
- "templates.test.display.select": "选择显示器...",
- "templates.test.duration": "采集时长(秒):",
- "templates.test.border_width": "边框宽度(像素):",
- "templates.test.run": "运行",
- "templates.test.running": "正在运行测试...",
- "templates.test.results.preview": "全幅采集预览",
- "templates.test.results.borders": "边框提取",
- "templates.test.results.top": "上",
- "templates.test.results.right": "右",
- "templates.test.results.bottom": "下",
- "templates.test.results.left": "左",
- "templates.test.results.performance": "性能",
- "templates.test.results.capture_time": "采集",
- "templates.test.results.extraction_time": "提取",
- "templates.test.results.total_time": "总计",
- "templates.test.results.max_fps": "最大 FPS",
- "templates.test.results.duration": "时长",
- "templates.test.results.frame_count": "帧数",
- "templates.test.results.actual_fps": "实际 FPS",
- "templates.test.results.avg_capture_time": "平均采集",
- "templates.test.results.resolution": "分辨率:",
- "templates.test.error.no_engine": "请选择采集引擎",
- "templates.test.error.no_display": "请选择显示器",
- "templates.test.error.failed": "测试失败",
- "devices.title": "设备",
- "device.select_type": "选择设备类型",
- "devices.add": "添加新设备",
- "devices.loading": "正在加载设备...",
- "devices.none": "尚未配置设备",
- "devices.failed": "加载设备失败",
- "devices.wled_config": "WLED 配置:",
- "devices.wled_note": "使用以下方式配置您的 WLED 设备(效果、分段、颜色顺序、功率限制等):",
- "devices.wled_link": "官方 WLED 应用",
- "devices.wled_note_or": "或内置的",
- "devices.wled_webui_link": "WLED Web UI",
- "devices.wled_note_webui": "(在浏览器中打开设备 IP 地址)。",
- "devices.wled_note2": "此控制器发送像素颜色数据并控制每个设备的亮度。",
- "device.scan": "自动发现",
- "device.scan.empty": "未找到设备",
- "device.scan.error": "网络扫描失败",
- "device.scan.already_added": "已添加",
- "device.scan.selected": "设备已选择",
- "device.type": "设备类型:",
- "device.type.hint": "选择 LED 控制器的类型",
- "device.type.wled": "WLED",
- "device.type.wled.desc": "通过HTTP/UDP控制的WiFi LED",
- "device.type.adalight": "Adalight",
- "device.type.adalight.desc": "Arduino串口LED协议",
- "device.type.ambiled": "AmbiLED",
- "device.type.ambiled.desc": "AmbiLED串口协议",
- "device.type.mqtt": "MQTT",
- "device.type.mqtt.desc": "通过MQTT代理发布LED数据",
- "device.type.ws": "WebSocket",
- "device.type.ws.desc": "通过WebSocket流式传输LED数据",
- "device.type.openrgb": "OpenRGB",
- "device.type.openrgb.desc": "通过OpenRGB控制RGB外设",
- "device.type.dmx": "DMX",
- "device.type.dmx.desc": "Art-Net / sACN (E1.31) 舞台灯光",
- "device.type.mock": "Mock",
- "device.type.mock.desc": "用于测试的虚拟设备",
- "device.type.espnow": "ESP-NOW",
- "device.type.espnow.desc": "Ultra-low-latency via ESP32 gateway",
- "device.type.hue": "Philips Hue",
- "device.type.hue.desc": "Hue Entertainment API streaming",
- "device.type.usbhid": "USB HID",
- "device.type.usbhid.desc": "USB RGB peripherals (keyboards, mice)",
- "device.type.spi": "SPI Direct",
- "device.type.spi.desc": "Raspberry Pi GPIO/SPI LED strips",
- "device.type.chroma": "Razer Chroma",
- "device.type.chroma.desc": "Razer peripherals via Chroma SDK",
- "device.type.gamesense": "SteelSeries",
- "device.type.gamesense.desc": "SteelSeries peripherals via GameSense",
- "device.chroma.device_type": "Peripheral Type:",
- "device.chroma.device_type.hint": "Which Razer peripheral to control via Chroma SDK",
- "device.gamesense.device_type": "Peripheral Type:",
- "device.gamesense.device_type.hint": "Which SteelSeries peripheral to control via GameSense",
- "device.espnow.peer_mac": "Peer MAC:",
- "device.espnow.peer_mac.hint": "MAC address of the remote ESP32 receiver (e.g. AA:BB:CC:DD:EE:FF)",
- "device.espnow.channel": "WiFi Channel:",
- "device.espnow.channel.hint": "WiFi channel (1-14). Must match the receiver's channel.",
- "device.hue.url": "Bridge IP:",
- "device.hue.url.hint": "IP address of your Hue bridge",
- "device.hue.username": "Bridge Username:",
- "device.hue.username.hint": "Hue bridge application key from pairing",
- "device.hue.client_key": "Client Key:",
- "device.hue.client_key.hint": "Entertainment API client key (hex string from pairing)",
- "device.hue.group_id": "Entertainment Group:",
- "device.hue.group_id.hint": "Entertainment configuration ID from your Hue bridge",
- "device.usbhid.url": "VID:PID:",
- "device.usbhid.url.hint": "USB Vendor:Product ID in hex (e.g. 1532:0084)",
- "device.spi.url": "GPIO/SPI Path:",
- "device.spi.url.hint": "GPIO pin or SPI device path (e.g. spi://gpio:18)",
- "device.spi.speed": "SPI Speed (Hz):",
- "device.spi.speed.hint": "SPI clock speed. 800000 Hz for WS2812, 2400000 Hz for APA102.",
- "device.spi.led_type": "LED Chipset:",
- "device.spi.led_type.hint": "Type of addressable LED strip connected to the GPIO/SPI pin",
- "device.spi.led_type.ws2812b.desc": "Most common, 800 KHz data, 3-wire RGB",
- "device.spi.led_type.ws2812.desc": "Original WS2812, 800 KHz, 3-wire RGB",
- "device.spi.led_type.ws2811.desc": "External driver IC, 400 KHz, 12V strips",
- "device.spi.led_type.sk6812.desc": "Samsung LED, 800 KHz, 3-wire RGB",
- "device.spi.led_type.sk6812_rgbw.desc": "SK6812 with dedicated white channel",
- "device.gamesense.peripheral.keyboard": "Keyboard",
- "device.gamesense.peripheral.keyboard.desc": "Per-key RGB illumination",
- "device.gamesense.peripheral.mouse": "Mouse",
- "device.gamesense.peripheral.mouse.desc": "Mouse RGB zones",
- "device.gamesense.peripheral.headset": "Headset",
- "device.gamesense.peripheral.headset.desc": "Headset earcup lighting",
- "device.gamesense.peripheral.mousepad": "Mousepad",
- "device.gamesense.peripheral.mousepad.desc": "Mousepad edge lighting zones",
- "device.gamesense.peripheral.indicator": "Indicator",
- "device.gamesense.peripheral.indicator.desc": "OLED/LED status indicator",
- "device.dmx_protocol": "DMX 协议:",
- "device.dmx_protocol.hint": "Art-Net 使用 UDP 端口 6454,sACN (E1.31) 使用 UDP 端口 5568",
- "device.dmx_protocol.artnet.desc": "UDP 单播,端口 6454",
- "device.dmx_protocol.sacn.desc": "组播/单播,端口 5568",
- "device.dmx_start_universe": "起始 Universe:",
- "device.dmx_start_universe.hint": "第一个 DMX universe (0-32767)。超过 170 个 LED 时自动使用多个 universe。",
- "device.dmx_start_channel": "起始通道:",
- "device.dmx_start_channel.hint": "universe 中的第一个 DMX 通道 (1-512)",
- "device.dmx.url": "IP 地址:",
- "device.dmx.url.hint": "DMX 节点的 IP 地址(例如 192.168.1.50)",
- "device.dmx.url.placeholder": "192.168.1.50",
- "device.serial_port": "串口:",
- "device.serial_port.hint": "选择 Adalight 设备的 COM 端口",
- "device.serial_port.none": "未找到串口",
- "device.serial_port.select": "选择端口...",
- "device.led_count_manual.hint": "灯带上的 LED 数量(必须与 Arduino 程序匹配)",
- "device.baud_rate": "波特率:",
- "device.baud_rate.hint": "串口通信速率。越高 FPS 越高,但需要与 Arduino 程序匹配。",
- "device.led_type": "LED 类型:",
- "device.led_type.hint": "RGB(3通道)或 RGBW(4通道,带独立白色)",
- "device.send_latency": "发送延迟(毫秒):",
- "device.send_latency.hint": "每帧模拟网络/串口延迟(毫秒)",
- "device.css_processing_template": "色带处理模板:",
- "device.css_processing_template.hint": "应用于此设备所有色带输出的默认处理模板",
- "device.mqtt_topic": "MQTT 主题:",
- "device.mqtt_topic.hint": "用于发布像素数据的 MQTT 主题路径(例如 mqtt://ledgrab/device/name)",
- "device.mqtt_topic.placeholder": "mqtt://ledgrab/device/客厅",
- "device.ws_url": "连接 URL:",
- "device.ws_url.hint": "客户端连接并接收 LED 数据的 WebSocket URL",
- "device.openrgb.url": "OpenRGB URL:",
- "device.openrgb.url.hint": "OpenRGB 服务器地址(例如 openrgb://localhost:6742/0)",
- "device.openrgb.zone": "区域:",
- "device.openrgb.zone.hint": "选择要控制的 LED 区域(全部不选则控制所有区域)",
- "device.openrgb.zone.loading": "加载区域中…",
- "device.openrgb.zone.error": "加载区域失败",
- "device.openrgb.mode": "区域模式:",
- "device.openrgb.mode.hint": "合并模式将所有区域作为一条连续 LED 灯带。独立模式让每个区域独立渲染完整效果。",
- "device.openrgb.mode.combined": "合并灯带",
- "device.openrgb.mode.separate": "独立区域",
- "device.openrgb.added_multiple": "已添加 {count} 个设备",
- "device.type.openrgb": "OpenRGB",
- "device.url.hint": "设备的 IP 地址或主机名(例如 http://192.168.1.100)",
- "device.name": "设备名称:",
- "device.name.placeholder": "客厅电视",
- "device.url": "地址:",
- "device.url.placeholder": "http://192.168.1.100",
- "device.led_count": "LED 数量:",
- "device.led_count.hint": "设备中配置的 LED 数量",
- "device.led_count.hint.auto": "从设备自动检测",
- "device.button.add": "添加设备",
- "device.button.start": "启动",
- "device.button.stop": "停止",
- "device.button.settings": "常规设置",
- "device.button.capture_settings": "采集设置",
- "device.button.calibrate": "校准",
- "device.button.remove": "移除",
- "device.button.webui": "打开设备 Web UI",
- "device.button.power_off": "关闭",
- "device.button.ping": "Ping 设备",
- "device.ping.online": "在线 ({ms}ms)",
- "device.ping.offline": "设备离线",
- "device.ping.error": "Ping 失败",
- "device.power.off_success": "设备已关闭",
- "device.status.connected": "已连接",
- "device.status.disconnected": "已断开",
- "device.status.error": "错误",
- "device.status.processing": "处理中",
- "device.status.idle": "空闲",
- "device.fps": "FPS:",
- "device.display": "显示器:",
- "device.remove.confirm": "确定要移除此设备吗?",
- "device.added": "设备添加成功",
- "device.removed": "设备移除成功",
- "device.started": "处理已启动",
- "device.stopped": "处理已停止",
- "device.metrics.actual_fps": "实际 FPS",
- "device.metrics.current_fps": "当前 FPS",
- "device.metrics.target_fps": "目标 FPS",
- "device.metrics.potential_fps": "潜在 FPS",
- "device.metrics.frames": "帧数",
- "device.metrics.frames_skipped": "已跳过",
- "device.metrics.keepalive": "心跳",
- "device.metrics.errors": "错误",
- "device.metrics.uptime": "运行时长",
- "device.metrics.timing": "管线时序:",
- "device.metrics.device_fps": "设备刷新率",
- "device.health.online": "在线",
- "device.health.offline": "离线",
- "device.health.streaming_unreachable": "流传输期间不可达",
- "device.health.checking": "检测中...",
- "device.last_seen.label": "最近检测",
- "device.last_seen.just_now": "刚刚",
- "device.last_seen.seconds": "%d秒前",
- "device.last_seen.minutes": "%d分钟前",
- "device.last_seen.hours": "%d小时前",
- "device.last_seen.days": "%d天前",
- "device.tutorial.start": "开始教程",
- "device.tip.metadata": "设备信息(LED 数量、类型、颜色通道)从设备自动检测",
- "device.tip.brightness": "滑动调节设备亮度",
- "device.tip.start": "启动或停止屏幕采集处理",
- "device.tip.settings": "配置设备常规设置(名称、地址、健康检查)",
- "device.tip.capture_settings": "配置采集设置(显示器、采集模板)",
- "device.tip.calibrate": "校准 LED 位置、方向和覆盖范围",
- "device.tip.webui": "打开设备内置的 Web 界面进行高级配置",
- "device.tip.add": "点击此处添加新的 LED 设备",
- "settings.title": "设置",
- "settings.tab.general": "常规",
- "settings.tab.backup": "备份",
- "settings.tab.mqtt": "MQTT",
- "settings.logs.open_viewer": "打开日志查看器",
- "settings.external_url.label": "外部 URL",
- "settings.external_url.hint": "设置后,此基础 URL 将用于 webhook 链接和其他用户可见的链接,代替自动检测的本地 IP。示例:https://myserver.example.com:8080",
- "settings.external_url.placeholder": "https://myserver.example.com:8080",
- "settings.external_url.save": "保存",
- "settings.external_url.saved": "外部 URL 已保存",
- "settings.external_url.save_error": "保存外部 URL 失败",
- "settings.general.title": "常规设置",
- "settings.capture.title": "采集设置",
- "settings.capture.saved": "采集设置已更新",
- "settings.capture.failed": "保存采集设置失败",
- "settings.brightness": "亮度:",
- "settings.brightness.hint": "此设备的全局亮度(0-100%)",
- "settings.url.hint": "设备的 IP 地址或主机名",
- "settings.display_index": "显示器:",
- "settings.display_index.hint": "为此设备采集哪个屏幕",
- "settings.fps": "目标 FPS:",
- "settings.fps.hint": "目标帧率(10-90)",
- "settings.capture_template": "引擎模板:",
- "settings.capture_template.hint": "此设备的屏幕采集引擎和配置",
- "settings.button.cancel": "取消",
- "settings.health_interval": "健康检查间隔(秒):",
- "settings.health_interval.hint": "检查设备状态的频率(5-600秒)",
- "settings.auto_shutdown": "自动恢复:",
- "settings.auto_shutdown.hint": "当目标停止或服务器关闭时恢复设备到空闲状态",
- "settings.button.save": "保存更改",
- "settings.saved": "设置保存成功",
- "settings.failed": "保存设置失败",
- "calibration.title": "LED 校准",
- "calibration.tip.led_count": "输入每条边的 LED 数量",
- "calibration.tip.start_corner": "点击角落设置起始位置",
- "calibration.tip.direction": "切换灯带方向(顺时针/逆时针)",
- "calibration.tip.offset": "设置 LED 偏移 — 从 LED 0 到起始角落的距离",
- "calibration.tip.span": "拖动绿色条调整覆盖范围",
- "calibration.tip.test": "点击边缘切换测试 LED",
- "calibration.tip.overlay": "切换屏幕叠加层以查看显示器上的 LED 位置和编号",
- "calibration.tip.toggle_inputs": "点击 LED 总数切换边缘输入",
- "calibration.tip.border_width": "从屏幕边缘采样多少像素来确定 LED 颜色",
- "calibration.tip.skip_leds_start": "跳过灯带起始端的 LED — 被跳过的 LED 保持关闭",
- "calibration.tip.skip_leds_end": "跳过灯带末尾端的 LED — 被跳过的 LED 保持关闭",
- "tour.welcome": "欢迎使用 LED Grab!快速导览将带您了解界面。使用方向键或按钮进行导航。",
- "tour.dashboard": "仪表盘 — 实时查看运行中的目标、自动化和设备状态。",
- "tour.targets": "目标 — 添加 WLED 设备,配置 LED 目标的捕获设置和校准。",
- "tour.sources": "来源 — 管理捕获模板、图片来源、音频来源和色带。",
- "tour.graph": "图表 — 所有实体及其连接的可视化概览。拖动端口进行连接,右键单击边线断开连接。",
- "tour.automations": "自动化 — 通过时间、音频或数值条件自动切换场景。",
- "tour.settings": "设置 — 备份和恢复配置,管理自动备份。",
- "tour.api": "API 文档 — 基于 Swagger 的交互式 REST API 文档。",
- "tour.search": "搜索 — 使用 Ctrl+K 快速查找并导航到任意实体。",
- "tour.theme": "主题 — 在深色和浅色模式之间切换。",
- "tour.accent": "主题色 — 自定义界面的强调颜色。",
- "tour.language": "语言 — 选择您偏好的界面语言。",
- "tour.restart": "重新开始导览",
- "tour.dash.perf": "性能 — 实时 FPS 图表、延迟指标和轮询间隔控制。",
- "tour.dash.running": "运行中的目标 — 实时流媒体指标和快速停止控制。",
- "tour.dash.stopped": "已停止的目标 — 一键启动。",
- "tour.dash.automations": "自动化 — 活动自动化状态和快速启用/禁用切换。",
- "tour.tgt.led_tab": "LED 标签 — 标准 LED 灯带目标,包含设备和色带配置。",
- "tour.tgt.devices": "设备 — 在网络中发现的 LED 控制器。",
- "tour.tgt.css": "色带 — 定义屏幕区域如何映射到 LED 段。",
- "tour.tgt.targets": "LED 目标 — 将设备、色带和捕获源组合进行流式传输。",
- "tour.tgt.kc_tab": "Key Colors — 使用颜色匹配代替像素映射的替代目标类型。",
- "tour.src.raw": "原始 — 来自显示器的实时屏幕捕获源。",
- "tour.src.templates": "捕获模板 — 可复用的捕获配置(分辨率、FPS、裁剪)。",
- "tour.src.static": "静态图片 — 使用图片文件测试您的设置。",
- "tour.src.processed": "处理 — 应用后处理效果,如模糊、亮度或色彩校正。",
- "tour.src.color_strip": "色带 — 定义屏幕区域如何映射到 LED 段。",
- "tour.src.audio": "音频 — 分析麦克风或系统音频以实现响应式 LED 效果。",
- "tour.src.value": "数值 — 用于自动化条件的数字数据源。",
- "tour.src.sync": "同步时钟 — 在多个源之间同步动画的共享定时器。",
- "tour.auto.list": "自动化 — 基于时间、音频或数值条件自动激活场景。",
- "tour.auto.add": "点击 + 创建包含条件和要激活场景的新自动化。",
- "tour.auto.card": "每张卡片显示自动化状态、条件和快速编辑/切换控制。",
- "tour.auto.scenes_list": "场景 — 保存的系统状态,自动化可以激活或您可以手动应用。",
- "tour.auto.scenes_add": "点击 + 将当前系统状态捕获为新的场景预设。",
- "tour.auto.scenes_card": "每个场景卡片显示目标/设备数量。点击编辑、重新捕获或激活。",
- "calibration.tutorial.start": "开始教程",
- "calibration.overlay_toggle": "叠加层",
- "calibration.start_position": "起始位置:",
- "calibration.position.bottom_left": "左下",
- "calibration.position.bottom_right": "右下",
- "calibration.position.top_left": "左上",
- "calibration.position.top_right": "右上",
- "calibration.direction": "方向:",
- "calibration.direction.clockwise": "顺时针",
- "calibration.direction.counterclockwise": "逆时针",
- "calibration.leds.top": "顶部 LED:",
- "calibration.leds.right": "右侧 LED:",
- "calibration.leds.bottom": "底部 LED:",
- "calibration.leds.left": "左侧 LED:",
- "calibration.offset": "LED 偏移:",
- "calibration.offset.hint": "从物理 LED 0 到起始角落的距离(沿灯带方向)",
- "calibration.skip_start": "跳过 LED(起始):",
- "calibration.skip_start.hint": "灯带起始端关闭的 LED 数量(0 = 无)",
- "calibration.skip_end": "跳过 LED(末尾):",
- "calibration.skip_end.hint": "灯带末尾端关闭的 LED 数量(0 = 无)",
- "calibration.border_width": "边框(像素):",
- "calibration.border_width.hint": "从屏幕边缘采样多少像素来确定 LED 颜色(1-100)",
- "calibration.button.cancel": "取消",
- "calibration.button.save": "保存",
- "calibration.saved": "校准保存成功",
- "calibration.failed": "保存校准失败",
- "server.healthy": "服务器在线",
- "server.offline": "服务器离线",
- "error.unauthorized": "未授权 - 请先登录",
- "error.network": "网络错误",
- "error.unknown": "发生错误",
- "modal.discard_changes": "有未保存的更改。是否放弃?",
- "confirm.title": "确认操作",
- "confirm.yes": "是",
- "confirm.no": "否",
- "confirm.stop_all": "停止所有运行中的目标?",
- "confirm.turn_off_device": "关闭此设备?",
- "common.loading": "加载中...",
- "common.delete": "删除",
- "common.edit": "编辑",
- "common.clone": "克隆",
- "common.none": "无",
- "common.none_no_cspt": "无(无处理模板)",
- "common.none_no_input": "无(无输入源)",
- "common.none_own_speed": "无(使用自身速度)",
- "common.undo": "撤销",
- "validation.required": "此字段为必填项",
- "bulk.processing": "处理中…",
- "api.error.timeout": "请求超时 — 请重试",
- "api.error.network": "网络错误 — 请检查连接",
- "palette.search": "搜索…",
- "section.filter.placeholder": "筛选...",
- "section.filter.reset": "清除筛选",
- "tags.label": "标签",
- "tags.hint": "为卡片分配标签以进行分组和筛选",
- "tags.placeholder": "添加标签...",
- "section.expand_all": "全部展开",
- "section.collapse_all": "全部折叠",
- "streams.title": "源",
- "streams.description": "源定义采集管线。原始源使用采集模板从显示器采集。处理源对另一个源应用后处理。将源分配给设备。",
- "streams.group.raw": "源",
- "streams.group.raw_templates": "引擎模板",
- "streams.group.processed": "源",
- "streams.group.proc_templates": "滤镜模板",
- "streams.group.css_processing": "处理模板",
- "streams.group.color_strip": "色带源",
- "streams.group.audio": "音频",
- "streams.group.audio_templates": "音频模板",
- "streams.section.streams": "源",
- "streams.add": "添加源",
- "streams.add.raw": "添加屏幕采集",
- "streams.add.processed": "添加处理源",
- "streams.edit": "编辑源",
- "streams.edit.raw": "编辑屏幕采集",
- "streams.edit.processed": "编辑处理源",
- "streams.name": "源名称:",
- "streams.name.placeholder": "我的源",
- "streams.type": "类型:",
- "streams.type.raw": "屏幕采集",
- "streams.type.processed": "已处理",
- "streams.display": "显示器:",
- "streams.display.hint": "采集哪个屏幕",
- "streams.capture_template": "引擎模板:",
- "streams.capture_template.hint": "定义屏幕采集方式的引擎模板",
- "streams.target_fps": "目标 FPS:",
- "streams.target_fps.hint": "采集的目标帧率(1-90)",
- "streams.source": "源:",
- "streams.source.hint": "要应用处理滤镜的源",
- "streams.pp_template": "滤镜模板:",
- "streams.pp_template.hint": "要应用到源的滤镜模板",
- "streams.description_label": "描述(可选):",
- "streams.description_placeholder": "描述此源...",
- "streams.created": "源创建成功",
- "streams.updated": "源更新成功",
- "streams.deleted": "源删除成功",
- "streams.delete.confirm": "确定要删除此源吗?",
- "streams.modal.loading": "加载中...",
- "streams.error.load": "加载源失败",
- "streams.error.required": "请填写所有必填项",
- "streams.error.delete": "删除源失败",
- "streams.test.title": "测试源",
- "streams.test.run": "运行",
- "streams.test.running": "正在测试源...",
- "streams.test.duration": "采集时长(秒):",
- "streams.test.error.failed": "源测试失败",
- "postprocessing.title": "滤镜模板",
- "postprocessing.description": "处理模板定义图像滤镜和色彩校正。将它们分配给处理图片源以实现跨设备的一致后处理。",
- "postprocessing.add": "添加滤镜模板",
- "postprocessing.edit": "编辑滤镜模板",
- "postprocessing.name": "模板名称:",
- "postprocessing.name.placeholder": "我的滤镜模板",
- "filters.select_type": "选择滤镜类型...",
- "filters.add": "添加滤镜",
- "filters.remove": "移除",
- "filters.drag_to_reorder": "拖动以重新排序",
- "filters.empty": "尚未添加滤镜。使用下方选择器添加滤镜。",
- "filters.brightness": "亮度",
- "filters.brightness.desc": "调整整体图像亮度",
- "filters.saturation": "饱和度",
- "filters.saturation.desc": "增强或降低色彩强度",
- "filters.gamma": "伽马",
- "filters.gamma.desc": "非线性亮度曲线校正",
- "filters.downscaler": "缩小",
- "filters.downscaler.desc": "降低分辨率以加快处理",
- "filters.pixelate": "像素化",
- "filters.pixelate.desc": "马赛克式块平均",
- "filters.auto_crop": "自动裁剪",
- "filters.auto_crop.desc": "移除信箱式内容的黑边",
- "filters.flip": "翻转",
- "filters.flip.desc": "水平或垂直镜像翻转",
- "filters.color_correction": "色彩校正",
- "filters.color_correction.desc": "白平衡和色温调整",
- "filters.filter_template": "滤镜模板",
- "filters.filter_template.desc": "嵌入另一个处理模板",
- "filters.css_filter_template": "色带滤镜模板",
- "filters.css_filter_template.desc": "嵌入另一个色带处理模板",
- "filters.frame_interpolation": "帧插值",
- "filters.frame_interpolation.desc": "帧间混合以获得更平滑的输出",
- "filters.noise_gate": "噪声门",
- "filters.noise_gate.desc": "抑制低于阈值的细微色彩变化",
- "filters.palette_quantization": "调色板量化",
- "filters.palette_quantization.desc": "将颜色减少到有限调色板",
- "filters.reverse": "反转",
- "filters.reverse.desc": "反转色带中的LED顺序",
- "postprocessing.description_label": "描述(可选):",
- "postprocessing.description_placeholder": "描述此模板...",
- "postprocessing.created": "模板创建成功",
- "postprocessing.updated": "模板更新成功",
- "postprocessing.deleted": "模板删除成功",
- "postprocessing.delete.confirm": "确定要删除此滤镜模板吗?",
- "postprocessing.error.load": "加载处理模板失败",
- "postprocessing.error.required": "请填写所有必填项",
- "postprocessing.error.delete": "删除处理模板失败",
- "postprocessing.config.show": "显示设置",
- "postprocessing.test.title": "测试滤镜模板",
- "postprocessing.test.source_stream": "源:",
- "postprocessing.test.running": "正在测试处理模板...",
- "postprocessing.test.error.no_stream": "请选择一个源",
- "postprocessing.test.error.failed": "处理模板测试失败",
- "css_processing.title": "色带处理模板",
- "css_processing.add": "添加色带处理模板",
- "css_processing.edit": "编辑色带处理模板",
- "css_processing.name": "模板名称:",
- "css_processing.name_placeholder": "我的色带处理模板",
- "css_processing.description_label": "描述(可选):",
- "css_processing.description_placeholder": "描述此模板...",
- "css_processing.created": "色带处理模板已创建",
- "css_processing.updated": "色带处理模板已更新",
- "css_processing.deleted": "色带处理模板已删除",
- "css_processing.delete.confirm": "确定要删除此色带处理模板吗?",
- "css_processing.error.required": "请填写所有必填字段",
- "css_processing.error.load": "加载色带处理模板出错",
- "css_processing.error.delete": "删除色带处理模板出错",
- "css_processing.error.clone_failed": "克隆色带处理模板失败",
- "device.button.stream_selector": "源设置",
- "device.stream_settings.title": "源设置",
- "device.stream_selector.label": "源:",
- "device.stream_selector.hint": "选择一个源来定义此设备采集和处理的内容",
- "device.stream_selector.none": "-- 未分配源 --",
- "device.stream_selector.saved": "源设置已更新",
- "device.stream_settings.border_width": "边框宽度(像素):",
- "device.stream_settings.border_width_hint": "从屏幕边缘采样多少像素来确定 LED 颜色(1-100)",
- "device.stream_settings.interpolation": "插值模式:",
- "device.stream_settings.interpolation.average": "平均",
- "device.stream_settings.interpolation.median": "中位数",
- "device.stream_settings.interpolation.dominant": "主色",
- "device.stream_settings.interpolation_hint": "如何从采样像素计算 LED 颜色",
- "device.stream_settings.smoothing": "平滑:",
- "device.stream_settings.smoothing_hint": "帧间时间混合(0=无,1=完全)。减少闪烁。",
- "device.tip.stream_selector": "为此设备配置图片源和 LED 投影设置",
- "streams.group.static_image": "静态图片",
- "streams.add.static_image": "添加静态图片源",
- "streams.edit.static_image": "编辑静态图片源",
- "streams.type.static_image": "静态图片",
- "streams.group.video": "视频",
- "streams.add.video": "添加视频源",
- "streams.edit.video": "编辑视频源",
- "picture_source.type.video": "视频",
- "picture_source.type.video.desc": "从视频文件、URL或YouTube流式传输帧",
- "picture_source.video.url": "视频URL:",
- "picture_source.video.url.hint": "本地文件路径、HTTP URL或YouTube URL",
- "picture_source.video.url.placeholder": "https://example.com/video.mp4",
- "picture_source.video.loop": "循环:",
- "picture_source.video.speed": "播放速度:",
- "picture_source.video.start_time": "开始时间(秒):",
- "picture_source.video.end_time": "结束时间(秒):",
- "picture_source.video.resolution_limit": "最大宽度(像素):",
- "picture_source.video.resolution_limit.hint": "解码时缩小视频以提高性能",
- "streams.image_source": "图片源:",
- "streams.image_source.placeholder": "https://example.com/image.jpg 或 C:\\path\\to\\image.png",
- "streams.image_source.hint": "输入图片的 URL(http/https)或本地文件路径",
- "streams.validate_image.validating": "正在验证...",
- "streams.validate_image.valid": "图片可访问",
- "streams.validate_image.invalid": "图片不可访问",
- "targets.title": "目标",
- "targets.description": "目标将色带源桥接到输出设备。每个目标引用一个设备和一个色带源。",
- "targets.subtab.wled": "LED",
- "targets.subtab.led": "LED",
- "targets.section.devices": "设备",
- "targets.section.color_strips": "色带源",
- "targets.section.targets": "目标",
- "targets.section.specific_settings": "特定设置",
- "targets.section.advanced": "高级",
- "targets.add": "添加目标",
- "targets.edit": "编辑目标",
- "targets.loading": "正在加载目标...",
- "targets.none": "尚未配置目标",
- "targets.failed": "加载目标失败",
- "targets.name": "目标名称:",
- "targets.name.placeholder": "我的目标",
- "targets.device": "设备:",
- "targets.device.hint": "选择要发送数据的 LED 设备",
- "targets.device.none": "-- 选择设备 --",
- "targets.color_strip_source": "色带源:",
- "targets.color_strip_source.hint": "选择为此目标提供 LED 颜色的色带源",
- "targets.no_css": "无源",
- "targets.source": "源:",
- "targets.source.hint": "要采集和处理的图片源",
- "targets.source.none": "-- 未分配源 --",
- "targets.metrics.pipeline": "管线详情",
- "targets.fps": "目标 FPS:",
- "targets.fps.hint": "采集和 LED 更新的目标帧率(1-90)",
- "targets.fps.rec": "硬件最大 ≈ {fps} fps({leds} 个 LED)",
- "targets.border_width": "边框宽度(像素):",
- "targets.border_width.hint": "从屏幕边缘采样多少像素来确定 LED 颜色(1-100)",
- "targets.interpolation": "插值模式:",
- "targets.interpolation.hint": "如何从采样像素计算 LED 颜色",
- "targets.interpolation.average": "平均",
- "targets.interpolation.median": "中位数",
- "targets.interpolation.dominant": "主色",
- "targets.smoothing": "平滑:",
- "targets.smoothing.hint": "帧间时间混合(0=无,1=完全)。减少闪烁。",
- "targets.keepalive_interval": "心跳间隔:",
- "targets.keepalive_interval.hint": "源静态时重新发送最后一帧的频率,保持设备在活动模式(0.5-5.0秒)",
- "targets.created": "目标创建成功",
- "targets.updated": "目标更新成功",
- "targets.deleted": "目标删除成功",
- "targets.delete.confirm": "确定要删除此目标吗?",
- "targets.error.load": "加载目标失败",
- "targets.error.required": "请填写所有必填项",
- "targets.error.name_required": "请输入目标名称",
- "targets.error.delete": "删除目标失败",
- "targets.button.start": "启动",
- "targets.button.stop": "停止",
- "targets.status.processing": "处理中",
- "targets.status.idle": "空闲",
- "targets.status.error": "错误",
- "targets.metrics.actual_fps": "实际 FPS",
- "targets.metrics.target_fps": "目标 FPS",
- "targets.metrics.frames": "帧数",
- "targets.metrics.errors": "错误",
- "targets.subtab.key_colors": "关键颜色",
- "targets.section.key_colors": "关键颜色目标",
- "kc.add": "添加关键颜色目标",
- "kc.edit": "编辑关键颜色目标",
- "kc.name": "目标名称:",
- "kc.name.placeholder": "我的关键颜色目标",
- "kc.source": "图片源:",
- "kc.source.hint": "从哪个图片源提取颜色",
- "kc.source.none": "-- 未分配源 --",
- "kc.fps": "提取 FPS:",
- "kc.fps.hint": "每秒提取颜色的次数(1-60)",
- "kc.interpolation": "颜色模式:",
- "kc.interpolation.hint": "如何从每个矩形中的像素计算关键颜色",
- "kc.interpolation.average": "平均",
- "kc.interpolation.median": "中位数",
- "kc.interpolation.dominant": "主色",
- "kc.interpolation.average.desc": "所有像素颜色的平均值",
- "kc.interpolation.median.desc": "每通道中间颜色值",
- "kc.interpolation.dominant.desc": "出现最频繁的颜色",
- "kc.smoothing": "平滑:",
- "kc.smoothing.hint": "提取间的时间混合(0=无,1=完全)",
- "kc.pattern_template": "图案模板:",
- "kc.pattern_template.hint": "选择用于颜色提取的矩形图案",
- "kc.pattern_template.none": "-- 选择图案模板 --",
- "kc.brightness_vs": "亮度源:",
- "kc.brightness_vs.hint": "可选的值源,每帧动态控制亮度(与手动亮度滑块相乘)",
- "kc.brightness_vs.none": "无(仅手动亮度)",
- "kc.created": "关键颜色目标创建成功",
- "kc.updated": "关键颜色目标更新成功",
- "kc.deleted": "关键颜色目标删除成功",
- "kc.delete.confirm": "确定要删除此关键颜色目标吗?",
- "kc.error.no_pattern": "请选择图案模板",
- "kc.error.required": "请填写所有必填项",
- "kc.colors.none": "尚未提取颜色",
- "kc.test": "测试",
- "kc.test.error": "测试失败",
- "targets.section.pattern_templates": "图案模板",
- "pattern.add": "添加图案模板",
- "pattern.edit": "编辑图案模板",
- "pattern.name": "模板名称:",
- "pattern.name.placeholder": "我的图案模板",
- "pattern.description_label": "描述(可选):",
- "pattern.description_placeholder": "描述此图案...",
- "pattern.rectangles": "矩形",
- "pattern.rect.name": "名称",
- "pattern.rect.x": "X",
- "pattern.rect.y": "Y",
- "pattern.rect.width": "宽",
- "pattern.rect.height": "高",
- "pattern.rect.add": "添加矩形",
- "pattern.rect.remove": "移除",
- "pattern.rect.empty": "尚未定义矩形。请至少添加一个矩形。",
- "pattern.created": "图案模板创建成功",
- "pattern.updated": "图案模板更新成功",
- "pattern.deleted": "图案模板删除成功",
- "pattern.delete.confirm": "确定要删除此图案模板吗?",
- "pattern.delete.referenced": "无法删除:此模板正被目标引用",
- "pattern.error.required": "请填写所有必填项",
- "pattern.visual_editor": "可视编辑器",
- "pattern.capture_bg": "采集背景",
- "pattern.source_for_bg": "背景源:",
- "pattern.source_for_bg.none": "-- 选择源 --",
- "pattern.delete_selected": "删除选中",
- "pattern.name.hint": "此矩形布局的描述性名称",
- "pattern.description.hint": "关于此图案使用位置或方式的可选说明",
- "pattern.visual_editor.hint": "点击 + 按钮添加矩形。拖动边缘调整大小,拖动内部移动位置。",
- "pattern.rectangles.hint": "用精确坐标(0.0 到 1.0)微调矩形位置和大小",
- "overlay.toggle": "切换屏幕叠加层",
- "overlay.button.show": "显示叠加层可视化",
- "overlay.button.hide": "隐藏叠加层可视化",
- "overlay.started": "叠加层可视化已启动",
- "overlay.stopped": "叠加层可视化已停止",
- "overlay.error.start": "启动叠加层失败",
- "overlay.error.stop": "停止叠加层失败",
- "dashboard.title": "仪表盘",
- "dashboard.section.targets": "目标",
- "dashboard.section.running": "运行中",
- "dashboard.section.stopped": "已停止",
- "dashboard.no_targets": "尚未配置目标",
- "dashboard.uptime": "运行时长",
- "dashboard.fps": "FPS",
- "dashboard.errors": "错误",
- "dashboard.device": "设备",
- "dashboard.stop_all": "全部停止",
- "dashboard.failed": "加载仪表盘失败",
- "dashboard.section.automations": "自动化",
- "dashboard.section.scenes": "场景预设",
- "dashboard.section.sync_clocks": "同步时钟",
- "dashboard.targets": "目标",
- "dashboard.section.performance": "系统性能",
- "dashboard.perf.cpu": "CPU",
- "dashboard.perf.ram": "内存",
- "dashboard.perf.gpu": "GPU",
- "dashboard.perf.unavailable": "不可用",
- "dashboard.perf.color": "图表颜色",
- "dashboard.poll_interval": "刷新间隔",
- "automations.title": "自动化",
- "automations.empty": "尚未配置自动化。创建一个以自动激活场景。",
- "automations.add": "添加自动化",
- "automations.edit": "编辑自动化",
- "automations.delete.confirm": "删除自动化 \"{name}\"?",
- "automations.name": "名称:",
- "automations.name.hint": "此自动化的描述性名称",
- "automations.name.placeholder": "我的自动化",
- "automations.enabled": "启用:",
- "automations.enabled.hint": "禁用的自动化即使满足条件也不会激活",
- "automations.condition_logic": "条件逻辑:",
- "automations.condition_logic.hint": "多个条件的组合方式:任一(或)或 全部(与)",
- "automations.condition_logic.or": "任一条件(或)",
- "automations.condition_logic.and": "全部条件(与)",
- "automations.condition_logic.or.desc": "任一条件匹配时触发",
- "automations.condition_logic.and.desc": "全部匹配时才触发",
- "automations.conditions": "条件:",
- "automations.conditions.hint": "决定此自动化何时激活的规则",
- "automations.conditions.add": "添加条件",
- "automations.conditions.empty": "无条件 — 启用后自动化始终处于活动状态",
- "automations.condition.always": "始终",
- "automations.condition.always.desc": "始终活跃",
- "automations.condition.always.hint": "自动化启用后立即激活并保持活动。",
- "automations.condition.startup": "启动",
- "automations.condition.startup.desc": "服务器启动时",
- "automations.condition.startup.hint": "服务器启动时激活,启用期间保持活动。",
- "automations.condition.application": "应用程序",
- "automations.condition.application.desc": "应用运行/聚焦",
- "automations.condition.application.apps": "应用程序:",
- "automations.condition.application.apps.hint": "进程名,每行一个(例如 firefox.exe)",
- "automations.condition.application.browse": "浏览",
- "automations.condition.application.search": "筛选进程...",
- "automations.condition.application.no_processes": "未找到进程",
- "automations.condition.application.match_type": "匹配类型:",
- "automations.condition.application.match_type.hint": "如何检测应用程序",
- "automations.condition.application.match_type.running": "运行中",
- "automations.condition.application.match_type.running.desc": "进程活跃",
- "automations.condition.application.match_type.topmost": "最前",
- "automations.condition.application.match_type.topmost.desc": "前台窗口",
- "automations.condition.application.match_type.topmost_fullscreen": "最前 + 全屏",
- "automations.condition.application.match_type.topmost_fullscreen.desc": "前台 + 全屏",
- "automations.condition.application.match_type.fullscreen": "全屏",
- "automations.condition.application.match_type.fullscreen.desc": "任意全屏应用",
- "automations.condition.time_of_day": "时段",
- "automations.condition.time_of_day.desc": "时间范围",
- "automations.condition.time_of_day.start_time": "开始时间:",
- "automations.condition.time_of_day.end_time": "结束时间:",
- "automations.condition.time_of_day.overnight_hint": "跨夜时段(如 22:00–06:00),请将开始时间设为晚于结束时间。",
- "automations.condition.system_idle": "系统空闲",
- "automations.condition.system_idle.desc": "空闲/活跃",
- "automations.condition.system_idle.idle_minutes": "空闲超时(分钟):",
- "automations.condition.system_idle.mode": "触发模式:",
- "automations.condition.system_idle.when_idle": "空闲时",
- "automations.condition.system_idle.when_active": "活跃时",
- "automations.condition.display_state": "显示器状态",
- "automations.condition.display_state.desc": "显示器开/关",
- "automations.condition.display_state.state": "显示器状态:",
- "automations.condition.display_state.on": "开启",
- "automations.condition.display_state.off": "关闭(休眠)",
- "automations.condition.mqtt": "MQTT",
- "automations.condition.mqtt.desc": "MQTT 消息",
- "automations.condition.mqtt.topic": "主题:",
- "automations.condition.mqtt.payload": "消息内容:",
- "automations.condition.mqtt.match_mode": "匹配模式:",
- "automations.condition.mqtt.match_mode.exact": "精确匹配",
- "automations.condition.mqtt.match_mode.contains": "包含",
- "automations.condition.mqtt.match_mode.regex": "正则表达式",
- "automations.condition.mqtt.hint": "当 MQTT 主题收到匹配的消息时激活",
- "automations.condition.webhook": "Webhook",
- "automations.condition.webhook.desc": "HTTP 回调",
- "automations.condition.webhook.hint": "通过外部服务的 HTTP 请求激活(Home Assistant、IFTTT、curl 等)",
- "automations.condition.webhook.url": "Webhook URL:",
- "automations.condition.webhook.copy": "复制",
- "automations.condition.webhook.copied": "已复制!",
- "automations.condition.webhook.save_first": "请先保存自动化以生成 Webhook URL",
- "automations.scene": "场景:",
- "automations.scene.hint": "条件满足时激活的场景预设",
- "automations.scene.search_placeholder": "搜索场景...",
- "automations.scene.none_selected": "无(无场景)",
- "automations.scene.none_available": "没有可用的场景",
- "automations.deactivation_mode": "停用方式:",
- "automations.deactivation_mode.hint": "条件不再满足时的行为",
- "automations.deactivation_mode.none": "无",
- "automations.deactivation_mode.none.desc": "保持当前状态",
- "automations.deactivation_mode.revert": "恢复",
- "automations.deactivation_mode.revert.desc": "恢复到之前的状态",
- "automations.deactivation_mode.fallback_scene": "备用",
- "automations.deactivation_mode.fallback_scene.desc": "激活备用场景",
- "automations.deactivation_scene": "备用场景:",
- "automations.deactivation_scene.hint": "自动化停用时激活的场景",
- "automations.status.active": "活动",
- "automations.status.inactive": "非活动",
- "automations.status.disabled": "已禁用",
- "automations.action.disable": "禁用",
- "automations.last_activated": "上次激活",
- "automations.logic.and": " 与 ",
- "automations.logic.or": " 或 ",
- "automations.logic.all": "全部",
- "automations.logic.any": "任一",
- "automations.updated": "自动化已更新",
- "automations.created": "自动化已创建",
- "automations.deleted": "自动化已删除",
- "automations.error.name_required": "名称为必填项",
- "automations.error.clone_failed": "克隆自动化失败",
- "scenes.title": "场景",
- "scenes.add": "捕获场景",
- "scenes.edit": "编辑场景",
- "scenes.name": "名称:",
- "scenes.name.hint": "此场景预设的描述性名称",
- "scenes.name.placeholder": "我的场景",
- "scenes.description": "描述:",
- "scenes.description.hint": "此场景功能的可选描述",
- "scenes.targets": "目标:",
- "scenes.targets.hint": "选择要包含在此场景快照中的目标",
- "scenes.targets.add": "添加目标",
- "scenes.targets.search_placeholder": "搜索目标...",
- "scenes.capture": "捕获",
- "scenes.activate": "激活场景",
- "scenes.recapture": "重新捕获当前状态",
- "scenes.delete": "删除场景",
- "scenes.targets_count": "目标",
- "scenes.captured": "场景已捕获",
- "scenes.updated": "场景已更新",
- "scenes.activated": "场景已激活",
- "scenes.activated_partial": "场景部分激活",
- "scenes.errors": "错误",
- "scenes.recaptured": "场景已重新捕获",
- "scenes.deleted": "场景已删除",
- "scenes.recapture_confirm": "将当前状态重新捕获到\"{name}\"中?",
- "scenes.delete_confirm": "删除场景\"{name}\"?",
- "scenes.error.name_required": "名称为必填项",
- "scenes.error.save_failed": "保存场景失败",
- "scenes.error.activate_failed": "激活场景失败",
- "scenes.error.recapture_failed": "重新捕获场景失败",
- "scenes.error.delete_failed": "删除场景失败",
- "scenes.cloned": "场景已克隆",
- "scenes.error.clone_failed": "克隆场景失败",
- "time.hours_minutes": "{h}时 {m}分",
- "time.minutes_seconds": "{m}分 {s}秒",
- "time.seconds": "{s}秒",
- "dashboard.type.led": "LED",
- "dashboard.type.kc": "关键颜色",
- "aria.close": "关闭",
- "aria.save": "保存",
- "aria.cancel": "取消",
- "aria.previous": "上一个",
- "aria.next": "下一个",
- "aria.hint": "显示提示",
- "color_strip.select_type": "选择色带类型",
- "color_strip.add": "添加色带源",
- "color_strip.edit": "编辑色带源",
- "color_strip.name": "名称:",
- "color_strip.name.placeholder": "墙壁灯带",
- "color_strip.picture_source": "图片源:",
- "color_strip.picture_source.hint": "用作 LED 颜色计算输入的屏幕采集源",
- "color_strip.fps": "目标 FPS:",
- "color_strip.fps.hint": "LED 颜色更新的目标帧率(10-90)",
- "color_strip.interpolation": "颜色模式:",
- "color_strip.interpolation.hint": "如何从采样的边框像素计算 LED 颜色",
- "color_strip.interpolation.average": "平均",
- "color_strip.interpolation.median": "中位数",
- "color_strip.interpolation.dominant": "主色",
- "color_strip.interpolation.average.desc": "将所有采样像素混合为平滑颜色",
- "color_strip.interpolation.median.desc": "取中间颜色值,减少异常值",
- "color_strip.interpolation.dominant.desc": "使用样本中出现最频繁的颜色",
- "color_strip.smoothing": "平滑:",
- "color_strip.smoothing.hint": "帧间时间混合(0=无,1=完全)。减少闪烁。",
- "color_strip.frame_interpolation": "帧插值:",
- "color_strip.frame_interpolation.hint": "在连续采集帧之间混合,以在采集速率较低时仍以完整目标 FPS 输出。减少慢速环境过渡时的可见阶梯效应。",
- "color_strip.color_corrections": "色彩校正",
- "color_strip.brightness": "亮度:",
- "color_strip.brightness.hint": "输出亮度倍数(0=关闭,1=不变,2=加倍)。在颜色提取后应用。",
- "color_strip.saturation": "饱和度:",
- "color_strip.saturation.hint": "颜色饱和度(0=灰度,1=不变,2=双倍饱和度)",
- "color_strip.gamma": "伽马:",
- "color_strip.gamma.hint": "伽马校正(1=无,<1=更亮的中间调,>1=更暗的中间调)",
- "color_strip.test_device": "测试设备:",
- "color_strip.test_device.hint": "选择一个设备,在点击边缘切换时发送测试像素",
- "color_strip.leds": "LED 数量",
- "color_strip.led_count": "LED 数量:",
- "color_strip.led_count.hint": "物理灯带上的 LED 总数。屏幕源:0 = 从校准自动获取(未映射到边缘的额外 LED 将为黑色)。静态颜色:设置为与设备 LED 数量匹配。",
- "color_strip.created": "色带源已创建",
- "color_strip.updated": "色带源已更新",
- "color_strip.deleted": "色带源已删除",
- "color_strip.delete.confirm": "确定要删除此色带源吗?",
- "color_strip.delete.referenced": "无法删除:此源正在被目标使用",
- "color_strip.error.name_required": "请输入名称",
- "color_strip.type": "类型:",
- "color_strip.type.hint": "图片源从屏幕采集推导 LED 颜色。静态颜色用单一颜色填充所有 LED。渐变在所有 LED 上分布颜色渐变。颜色循环平滑循环用户定义的颜色列表。组合将多个源作为混合图层叠加。音频响应从实时音频输入驱动 LED。API 输入通过 REST 或 WebSocket 从外部客户端接收原始 LED 颜色。",
- "color_strip.type.picture": "图片源",
- "color_strip.type.picture.desc": "从屏幕捕获获取颜色",
- "color_strip.type.picture_advanced": "多显示器",
- "color_strip.type.picture_advanced.desc": "跨显示器的线条校准",
- "color_strip.type.static": "静态颜色",
- "color_strip.type.static.desc": "单色填充",
- "color_strip.type.gradient": "渐变",
- "color_strip.type.gradient.desc": "LED上的平滑颜色过渡",
- "color_strip.type.color_cycle": "颜色循环",
- "color_strip.type.color_cycle.desc": "循环切换颜色列表",
- "color_strip.static_color": "颜色:",
- "color_strip.static_color.hint": "将发送到灯带上所有 LED 的纯色。",
- "color_strip.gradient.preview": "渐变:",
- "color_strip.gradient.preview.hint": "可视预览。点击下方标记轨道添加色标。拖动标记重新定位。",
- "color_strip.gradient.stops": "色标:",
- "color_strip.gradient.stops.hint": "每个色标在相对位置定义一种颜色(0.0 = 起始,1.0 = 结束)。↔ 按钮添加右侧颜色以在该色标处创建硬边。",
- "color_strip.gradient.stops_count": "个色标",
- "color_strip.gradient.add_stop": "+ 添加色标",
- "color_strip.gradient.position": "位置(0.0-1.0)",
- "color_strip.gradient.bidir.hint": "在此色标右侧添加第二种颜色以在渐变中创建硬边。",
- "color_strip.gradient.min_stops": "渐变至少需要 2 个色标",
- "color_strip.gradient.preset": "预设:",
- "color_strip.gradient.preset.hint": "加载预定义的渐变调色板。选择预设将替换当前色标。",
- "color_strip.gradient.preset.custom": "— 自定义 —",
- "color_strip.gradient.preset.rainbow": "彩虹",
- "color_strip.gradient.preset.sunset": "日落",
- "color_strip.gradient.preset.ocean": "海洋",
- "color_strip.gradient.preset.forest": "森林",
- "color_strip.gradient.preset.fire": "火焰",
- "color_strip.gradient.preset.lava": "熔岩",
- "color_strip.gradient.preset.aurora": "极光",
- "color_strip.gradient.preset.ice": "冰",
- "color_strip.gradient.preset.warm": "暖色",
- "color_strip.gradient.preset.cool": "冷色",
- "color_strip.gradient.preset.neon": "霓虹",
- "color_strip.gradient.preset.pastel": "柔和",
- "color_strip.gradient.preset.save_button": "保存为预设…",
- "color_strip.gradient.preset.save_prompt": "输入预设名称:",
- "color_strip.gradient.preset.saved": "预设已保存",
- "color_strip.gradient.preset.deleted": "预设已删除",
- "color_strip.gradient.preset.apply": "应用",
- "color_strip.animation": "动画",
- "color_strip.animation.type": "效果:",
- "color_strip.animation.type.hint": "要应用的动画效果。",
- "color_strip.animation.type.none": "无(无动画效果)",
- "color_strip.animation.type.none.desc": "静态颜色,无动画",
- "color_strip.animation.type.breathing": "呼吸",
- "color_strip.animation.type.breathing.desc": "平滑的亮度渐入渐出",
- "color_strip.animation.type.color_cycle": "颜色循环",
- "color_strip.animation.type.gradient_shift": "渐变移动",
- "color_strip.animation.type.gradient_shift.desc": "渐变沿灯带滑动",
- "color_strip.animation.type.wave": "波浪",
- "color_strip.animation.type.wave.desc": "沿灯带移动的正弦亮度波",
- "color_strip.animation.type.strobe": "频闪",
- "color_strip.animation.type.strobe.desc": "快速开/关闪烁",
- "color_strip.animation.type.sparkle": "闪烁",
- "color_strip.animation.type.sparkle.desc": "随机 LED 短暂闪亮",
- "color_strip.animation.type.pulse": "脉冲",
- "color_strip.animation.type.pulse.desc": "快速衰减的尖锐亮度脉冲",
- "color_strip.animation.type.candle": "烛光",
- "color_strip.animation.type.candle.desc": "温暖的类似蜡烛的闪烁光芒",
- "color_strip.animation.type.rainbow_fade": "彩虹渐变",
- "color_strip.animation.type.rainbow_fade.desc": "循环整个色相光谱",
- "color_strip.animation.speed": "速度:",
- "color_strip.animation.speed.hint": "动画速度倍数。1.0 ≈ 呼吸效果每秒一个循环;更高值循环更快。",
- "color_strip.color_cycle.colors": "颜色:",
- "color_strip.color_cycle.colors.hint": "平滑循环的颜色列表。至少需要 2 种。默认为全彩虹光谱。",
- "color_strip.color_cycle.add_color": "+ 添加颜色",
- "color_strip.color_cycle.speed": "速度:",
- "color_strip.color_cycle.speed.hint": "循环速度倍数。1.0 ≈ 每 20 秒一个完整循环;更高值循环更快。",
- "color_strip.color_cycle.min_colors": "颜色循环至少需要 2 种颜色",
- "color_strip.type.effect": "效果",
- "color_strip.type.effect.desc": "程序化效果:火焰、等离子、极光",
- "color_strip.type.effect.hint": "实时生成的程序化 LED 效果(火焰、流星、等离子、噪声、极光)。",
- "color_strip.type.composite": "组合",
- "color_strip.type.composite.desc": "叠加和混合多个源",
- "color_strip.type.composite.hint": "将多个色带源作为图层叠加,支持混合模式和不透明度。",
- "color_strip.type.mapped": "映射",
- "color_strip.type.mapped.desc": "为LED区域分配源",
- "color_strip.type.mapped.hint": "将不同色带源分配到不同 LED 范围(区域)。与组合的图层混合不同,映射将源并排放置。",
- "color_strip.type.audio": "音频响应",
- "color_strip.type.audio.desc": "由音频输入驱动LED",
- "color_strip.type.audio.hint": "LED 颜色由实时音频输入驱动 — 系统音频或麦克风。",
- "color_strip.type.api_input": "API 输入",
- "color_strip.type.api_input.desc": "从外部应用接收颜色",
- "color_strip.type.api_input.hint": "通过 REST POST 或 WebSocket 从外部客户端接收原始 LED 颜色数组。用于与自定义软件、家庭自动化或任何能发送 HTTP 请求的系统集成。",
- "color_strip.api_input.fallback_color": "备用颜色:",
- "color_strip.api_input.fallback_color.hint": "超时未收到数据时显示的颜色。启动时和连接丢失后 LED 将显示此颜色。",
- "color_strip.api_input.timeout": "超时(秒):",
- "color_strip.api_input.timeout.hint": "等待新颜色数据多长时间后恢复为备用颜色。设为 0 表示永不超时。",
- "color_strip.api_input.endpoints": "推送端点:",
- "color_strip.api_input.endpoints.hint": "使用这些 URL 从外部应用程序推送 LED 颜色数据。REST 接受 JSON,WebSocket 接受 JSON 和原始二进制帧。",
- "color_strip.api_input.save_first": "请先保存源以查看推送端点 URL。",
- "color_strip.type.notification": "通知",
- "color_strip.type.notification.desc": "通过Webhook触发的一次性效果",
- "color_strip.type.notification.hint": "通过 Webhook 触发时显示一次性视觉效果(闪烁、脉冲、扫描)。设计为组合源中的叠加层。",
- "color_strip.notification.effect": "效果:",
- "color_strip.notification.effect.hint": "通知触发时的视觉效果。闪烁线性衰减,脉冲平滑钟形曲线,扫描从左到右填充后衰减。",
- "color_strip.notification.effect.flash": "闪烁",
- "color_strip.notification.effect.flash.desc": "瞬时点亮,线性衰减",
- "color_strip.notification.effect.pulse": "脉冲",
- "color_strip.notification.effect.pulse.desc": "平滑钟形发光",
- "color_strip.notification.effect.sweep": "扫描",
- "color_strip.notification.effect.sweep.desc": "从左到右填充然后消失",
- "color_strip.notification.duration": "持续时间(毫秒):",
- "color_strip.notification.duration.hint": "通知效果播放的时长(毫秒)。",
- "color_strip.notification.default_color": "默认颜色:",
- "color_strip.notification.default_color.hint": "当通知没有应用特定颜色映射时使用的颜色。",
- "color_strip.notification.filter_mode": "应用过滤:",
- "color_strip.notification.filter_mode.hint": "按应用名称过滤通知。关闭=接受全部,白名单=仅列出的应用,黑名单=排除列出的应用。",
- "color_strip.notification.filter_mode.off": "关闭",
- "color_strip.notification.filter_mode.whitelist": "白名单",
- "color_strip.notification.filter_mode.blacklist": "黑名单",
- "color_strip.notification.filter_mode.off.desc": "接受所有通知",
- "color_strip.notification.filter_mode.whitelist.desc": "仅列出的应用",
- "color_strip.notification.filter_mode.blacklist.desc": "排除列出的应用",
- "color_strip.notification.filter_list": "应用列表:",
- "color_strip.notification.filter_list.hint": "每行一个应用名称。使用「浏览」从运行中的进程中选择。",
- "color_strip.notification.filter_list.placeholder": "Discord\nSlack\nTelegram",
- "color_strip.notification.app_colors": "应用颜色",
- "color_strip.notification.app_colors.label": "颜色映射:",
- "color_strip.notification.app_colors.hint": "每个应用的自定义通知颜色。每行将一个应用名称映射到特定颜色。",
- "color_strip.notification.app_colors.add": "+ 添加映射",
- "color_strip.notification.endpoint": "Webhook 端点:",
- "color_strip.notification.endpoint.hint": "使用此 URL 从外部系统触发通知。POST 请求可选 JSON:{\"app\": \"AppName\", \"color\": \"#FF0000\"}。",
- "color_strip.notification.save_first": "请先保存源以查看 Webhook 端点 URL。",
- "color_strip.notification.app_count": "个应用",
- "color_strip.notification.test": "测试通知",
- "color_strip.notification.test.ok": "通知已发送",
- "color_strip.notification.test.no_streams": "此源没有运行中的流",
- "color_strip.notification.test.error": "发送通知失败",
- "color_strip.notification.history.title": "通知历史",
- "color_strip.notification.history.hint": "监听器捕获的最近OS通知(最新在前),最多50条。",
- "color_strip.notification.history.empty": "尚未捕获任何通知",
- "color_strip.notification.history.unavailable": "此平台不支持OS通知监听器",
- "color_strip.notification.history.error": "加载通知历史失败",
- "color_strip.notification.history.refresh": "刷新",
- "color_strip.notification.history.unknown_app": "未知应用",
- "color_strip.notification.history.fired": "触发的流数量",
- "color_strip.notification.history.filtered": "过滤的流数量",
- "color_strip.test.title": "预览测试",
- "color_strip.test.connecting": "连接中...",
- "color_strip.test.error": "无法连接到预览流",
- "color_strip.test.led_count": "LED数量:",
- "color_strip.test.fps": "FPS:",
- "color_strip.test.receive_fps": "接收帧率",
- "color_strip.test.apply": "应用",
- "color_strip.test.composite": "合成",
- "color_strip.preview.title": "实时预览",
- "color_strip.preview.not_connected": "未连接",
- "color_strip.preview.connecting": "连接中...",
- "color_strip.preview.connected": "已连接",
- "color_strip.preview.unsupported": "此源类型不支持预览",
- "color_strip.type.daylight": "日光循环",
- "color_strip.type.daylight.desc": "模拟24小时自然日光变化",
- "color_strip.type.daylight.hint": "模拟太阳在24小时内的色温变化——从温暖的日出到冷白的日光,再到温暖的日落和昏暗的夜晚。",
- "color_strip.daylight.speed": "速度:",
- "color_strip.daylight.speed.hint": "循环速度倍数。1.0 = 约4分钟完成一个完整的昼夜循环。",
- "color_strip.daylight.use_real_time": "使用实时时间:",
- "color_strip.daylight.use_real_time.hint": "启用后,LED颜色匹配计算机的实际时间。速度设置将被忽略。",
- "color_strip.daylight.real_time": "实时",
- "color_strip.daylight.latitude": "纬度:",
- "color_strip.daylight.latitude.hint": "地理纬度(-90到90)。影响实时模式下的日出/日落时间。",
- "color_strip.type.candlelight": "烛光",
- "color_strip.type.candlelight.desc": "逼真的烛光闪烁模拟",
- "color_strip.type.candlelight.hint": "在所有LED上模拟逼真的蜡烛闪烁,具有温暖色调和有机闪烁模式。",
- "color_strip.candlelight.color": "基础颜色:",
- "color_strip.candlelight.color.hint": "蜡烛火焰的温暖基础颜色。默认为自然温暖的琥珀色。",
- "color_strip.candlelight.intensity": "闪烁强度:",
- "color_strip.candlelight.intensity.hint": "蜡烛闪烁程度。低值产生柔和光芒,高值模拟风中的蜡烛。",
- "color_strip.candlelight.num_candles_label": "蜡烛数量:",
- "color_strip.candlelight.num_candles": "支蜡烛",
- "color_strip.candlelight.num_candles.hint": "灯带上独立蜡烛光源的数量。每支蜡烛有自己的闪烁模式。",
- "color_strip.candlelight.speed": "闪烁速度:",
- "color_strip.candlelight.speed.hint": "闪烁动画的速度。较高的值产生更快、更不安定的火焰。",
- "color_strip.type.processed": "已处理",
- "color_strip.type.processed.desc": "将处理模板应用于另一个源",
- "color_strip.type.processed.hint": "包装现有色带源并通过滤镜链处理其输出。",
- "color_strip.processed.input": "源:",
- "color_strip.processed.input.hint": "将被处理的色带源",
- "color_strip.processed.template": "处理模板:",
- "color_strip.processed.template.hint": "应用于输入源输出的滤镜链",
- "color_strip.processed.error.no_input": "请选择输入源",
- "color_strip.composite.layers": "图层:",
- "color_strip.composite.layers.hint": "叠加多个色带源。第一个图层在底部,最后一个在顶部。每个图层可以有自己的混合模式和不透明度。",
- "color_strip.composite.add_layer": "+ 添加图层",
- "color_strip.composite.source": "源",
- "color_strip.composite.blend_mode": "混合",
- "color_strip.composite.blend_mode.normal": "正常",
- "color_strip.composite.blend_mode.normal.desc": "标准 Alpha 混合",
- "color_strip.composite.blend_mode.add": "叠加",
- "color_strip.composite.blend_mode.add.desc": "通过叠加颜色提亮",
- "color_strip.composite.blend_mode.multiply": "正片叠底",
- "color_strip.composite.blend_mode.multiply.desc": "通过相乘颜色变暗",
- "color_strip.composite.blend_mode.screen": "滤色",
- "color_strip.composite.blend_mode.screen.desc": "提亮,正片叠底的反转",
- "color_strip.composite.blend_mode.override": "覆盖",
- "color_strip.composite.blend_mode.override.desc": "黑色=透明,亮色=不透明",
- "color_strip.composite.opacity": "不透明度",
- "color_strip.composite.brightness": "亮度",
- "color_strip.composite.brightness.none": "无(全亮度)",
- "color_strip.composite.processing": "处理",
- "color_strip.composite.enabled": "启用",
- "color_strip.composite.error.min_layers": "至少需要 1 个图层",
- "color_strip.composite.error.no_source": "每个图层必须选择一个源",
- "color_strip.composite.layers_count": "个图层",
- "color_strip.mapped.zones": "区域:",
- "color_strip.mapped.zones.hint": "每个区域将色带源映射到特定 LED 范围。区域并排放置 — 区域之间的间隙保持黑色。",
- "color_strip.mapped.add_zone": "+ 添加区域",
- "color_strip.mapped.zone_source": "源",
- "color_strip.mapped.zone_start": "起始 LED",
- "color_strip.mapped.zone_end": "结束 LED",
- "color_strip.mapped.zone_reverse": "反转",
- "color_strip.mapped.zones_count": "个区域",
- "color_strip.mapped.select_source": "搜索源...",
- "color_strip.mapped.error.no_source": "每个区域必须选择一个源",
- "color_strip.audio.visualization": "可视化:",
- "color_strip.audio.visualization.hint": "音频数据如何渲染到 LED。",
- "color_strip.audio.viz.spectrum": "频谱分析",
- "color_strip.audio.viz.spectrum.desc": "频率条分布在灯带上",
- "color_strip.audio.viz.beat_pulse": "节拍脉冲",
- "color_strip.audio.viz.beat_pulse.desc": "所有LED随节拍脉动",
- "color_strip.audio.viz.vu_meter": "VU 表",
- "color_strip.audio.viz.vu_meter.desc": "音量填充灯带",
- "color_strip.audio.source": "音频源:",
- "color_strip.audio.source.hint": "此可视化的音频源。可以是多声道(设备)或单声道(单通道)源。在源标签页中创建和管理音频源。",
- "color_strip.audio.sensitivity": "灵敏度:",
- "color_strip.audio.sensitivity.hint": "音频电平的增益倍数。更高值使 LED 对较安静的声音也有反应。",
- "color_strip.audio.smoothing": "平滑:",
- "color_strip.audio.smoothing.hint": "帧间时间平滑。更高值产生更平滑但反应较慢的视觉效果。",
- "color_strip.audio.palette": "调色板:",
- "color_strip.audio.palette.hint": "用于频谱条或节拍脉冲着色的调色板。",
- "color_strip.audio.color": "基础颜色:",
- "color_strip.audio.color.hint": "VU 表条的低电平颜色。",
- "color_strip.audio.color_peak": "峰值颜色:",
- "color_strip.audio.color_peak.hint": "VU 表条顶部的高电平颜色。",
- "color_strip.audio.mirror": "镜像:",
- "color_strip.audio.mirror.hint": "从中心向外镜像频谱:低音在中间,高音在两端。",
- "color_strip.effect.type": "效果类型:",
- "color_strip.effect.type.hint": "选择程序化算法。",
- "color_strip.effect.fire": "火焰",
- "color_strip.effect.fire.desc": "模拟带热量扩散的上升火焰的元胞自动机",
- "color_strip.effect.meteor": "流星",
- "color_strip.effect.meteor.desc": "明亮头部沿灯带移动,带指数衰减的尾迹",
- "color_strip.effect.plasma": "等离子",
- "color_strip.effect.plasma.desc": "映射到调色板的重叠正弦波 — 经典演示场景效果",
- "color_strip.effect.noise": "噪声",
- "color_strip.effect.noise.desc": "滚动的分形值噪声映射到调色板",
- "color_strip.effect.aurora": "极光",
- "color_strip.effect.aurora.desc": "漂移和混合的分层噪声带 — 北极光风格",
- "color_strip.effect.speed": "速度:",
- "color_strip.effect.speed.hint": "效果动画的速度倍数(0.1 = 非常慢,10.0 = 非常快)。",
- "color_strip.effect.palette": "调色板:",
- "color_strip.effect.palette.hint": "用于将效果值映射到 RGB 颜色的调色板。",
- "color_strip.effect.color": "流星颜色:",
- "color_strip.effect.color.hint": "流星效果的头部颜色。",
- "color_strip.effect.intensity": "强度:",
- "color_strip.effect.intensity.hint": "效果强度 — 控制火花率(火焰)、尾迹衰减(流星)或亮度范围(极光)。",
- "color_strip.effect.scale": "比例:",
- "color_strip.effect.scale.hint": "空间比例 — 波频率(等离子)、缩放级别(噪声)或带宽(极光)。",
- "color_strip.effect.mirror": "镜像:",
- "color_strip.effect.mirror.hint": "反弹模式 — 流星在灯带末端反转方向而不是循环。",
- "color_strip.palette.fire": "火焰",
- "color_strip.palette.ocean": "海洋",
- "color_strip.palette.lava": "熔岩",
- "color_strip.palette.forest": "森林",
- "color_strip.palette.rainbow": "彩虹",
- "color_strip.palette.aurora": "极光",
- "color_strip.palette.sunset": "日落",
- "color_strip.palette.ice": "冰",
- "audio_source.title": "音频源",
- "audio_source.group.multichannel": "多声道",
- "audio_source.group.mono": "单声道",
- "audio_source.add": "添加音频源",
- "audio_source.add.multichannel": "添加多声道源",
- "audio_source.add.mono": "添加单声道源",
- "audio_source.edit": "编辑音频源",
- "audio_source.edit.multichannel": "编辑多声道源",
- "audio_source.edit.mono": "编辑单声道源",
- "audio_source.name": "名称:",
- "audio_source.name.placeholder": "系统音频",
- "audio_source.name.hint": "此音频源的描述性名称",
- "audio_source.type": "类型:",
- "audio_source.type.hint": "多声道从物理音频设备采集所有通道。单声道从多声道源提取单个通道。",
- "audio_source.type.multichannel": "多声道",
- "audio_source.type.mono": "单声道",
- "audio_source.device": "音频设备:",
- "audio_source.device.hint": "音频输入源。回环设备采集系统音频输出;输入设备采集麦克风或线路输入。",
- "audio_source.refresh_devices": "刷新设备",
- "audio_source.parent": "父源:",
- "audio_source.parent.hint": "要从中提取通道的多声道源",
- "audio_source.channel": "通道:",
- "audio_source.channel.hint": "从多声道源提取哪个音频通道",
- "audio_source.channel.mono": "单声道(左+右混合)",
- "audio_source.channel.left": "左",
- "audio_source.channel.right": "右",
- "audio_source.description": "描述(可选):",
- "audio_source.description.placeholder": "描述此音频源...",
- "audio_source.description.hint": "关于此音频源的可选说明",
- "audio_source.created": "音频源已创建",
- "audio_source.updated": "音频源已更新",
- "audio_source.deleted": "音频源已删除",
- "audio_source.delete.confirm": "确定要删除此音频源吗?",
- "audio_source.error.name_required": "请输入名称",
- "audio_source.audio_template": "音频模板:",
- "audio_source.audio_template.hint": "定义此设备使用哪个引擎和设置的音频采集模板",
- "audio_source.test": "测试",
- "audio_source.test.title": "测试音频源",
- "audio_source.test.rms": "RMS",
- "audio_source.test.peak": "峰值",
- "audio_source.test.beat": "节拍",
- "audio_source.test.connecting": "连接中...",
- "audio_source.test.error": "音频测试失败",
- "audio_template.test": "测试",
- "audio_template.test.title": "测试音频模板",
- "audio_template.test.device": "音频设备:",
- "audio_template.test.device.hint": "选择测试期间要采集的音频设备",
- "audio_template.test.run": "运行",
- "audio_template.title": "音频模板",
- "audio_template.add": "添加音频模板",
- "audio_template.edit": "编辑音频模板",
- "audio_template.name": "模板名称:",
- "audio_template.name.placeholder": "我的音频模板",
- "audio_template.description.label": "描述(可选):",
- "audio_template.description.placeholder": "描述此模板...",
- "audio_template.engine": "音频引擎:",
- "audio_template.engine.hint": "选择要使用的音频采集后端。WASAPI 仅限 Windows 并支持回环。Sounddevice 支持跨平台。",
- "audio_template.engine.unavailable": "不可用",
- "audio_template.engine.unavailable.hint": "此引擎在您的系统上不可用",
- "audio_template.config": "配置",
- "audio_template.config.show": "显示配置",
- "audio_template.created": "音频模板已创建",
- "audio_template.updated": "音频模板已更新",
- "audio_template.deleted": "音频模板已删除",
- "audio_template.delete.confirm": "确定要删除此音频模板吗?",
- "audio_template.error.load": "加载音频模板失败",
- "audio_template.error.engines": "加载音频引擎失败",
- "audio_template.error.required": "请填写所有必填项",
- "audio_template.error.delete": "删除音频模板失败",
- "streams.group.value": "值源",
- "streams.group.sync": "同步时钟",
- "tree.group.picture": "图片源",
- "tree.group.capture": "屏幕采集",
- "tree.group.static": "静态",
- "tree.group.processing": "已处理",
- "tree.group.strip": "色带",
- "tree.group.audio": "音频",
- "tree.group.utility": "工具",
- "tree.leaf.sources": "源",
- "tree.leaf.engine_templates": "引擎模板",
- "tree.leaf.images": "图片",
- "tree.leaf.video": "视频",
- "tree.leaf.filter_templates": "滤镜模板",
- "tree.leaf.processing_templates": "处理模板",
- "tree.leaf.templates": "模板",
- "value_source.group.title": "值源",
- "value_source.select_type": "选择值源类型",
- "value_source.add": "添加值源",
- "value_source.edit": "编辑值源",
- "value_source.name": "名称:",
- "value_source.name.placeholder": "亮度脉冲",
- "value_source.name.hint": "此值源的描述性名称",
- "value_source.type": "类型:",
- "value_source.type.hint": "静态输出固定值。动画循环波形。音频响应声音输入。自适应类型根据时间或场景内容自动调节亮度。",
- "value_source.type.static": "静态",
- "value_source.type.static.desc": "固定输出值",
- "value_source.type.animated": "动画",
- "value_source.type.animated.desc": "循环波形变化",
- "value_source.type.audio": "音频",
- "value_source.type.audio.desc": "响应声音输入",
- "value_source.type.adaptive_time": "自适应(时间)",
- "value_source.type.adaptive_time.desc": "按时间自动调节",
- "value_source.type.adaptive_scene": "自适应(场景)",
- "value_source.type.adaptive_scene.desc": "按场景内容调节",
- "value_source.type.daylight": "日光周期",
- "value_source.type.daylight.desc": "亮度跟随日夜周期",
- "value_source.daylight.speed": "速度:",
- "value_source.daylight.speed.hint": "周期速度倍率。1.0 = 完整日夜周期约4分钟。",
- "value_source.daylight.use_real_time": "使用实时:",
- "value_source.daylight.use_real_time.hint": "启用后,亮度跟随实际时间。速度设置将被忽略。",
- "value_source.daylight.enable_real_time": "跟随系统时钟",
- "value_source.daylight.latitude": "纬度:",
- "value_source.daylight.latitude.hint": "地理纬度(-90到90)。影响实时模式下的日出/日落时间。",
- "value_source.daylight.real_time": "实时",
- "value_source.daylight.speed_label": "速度",
- "value_source.value": "值:",
- "value_source.value.hint": "固定输出值(0.0 = 关闭,1.0 = 最大亮度)",
- "value_source.waveform": "波形:",
- "value_source.waveform.hint": "亮度动画循环的形状",
- "value_source.waveform.sine": "正弦",
- "value_source.waveform.triangle": "三角",
- "value_source.waveform.square": "方波",
- "value_source.waveform.sawtooth": "锯齿",
- "value_source.speed": "速度(周期/分):",
- "value_source.speed.hint": "每分钟周期数 — 波形重复的速度(1 = 非常慢,120 = 非常快)",
- "value_source.min_value": "最小值:",
- "value_source.min_value.hint": "波形周期的最小输出",
- "value_source.max_value": "最大值:",
- "value_source.max_value.hint": "波形周期的最大输出",
- "value_source.audio_source": "音频源:",
- "value_source.audio_source.hint": "要读取音频电平的音频源(多声道或单声道)",
- "value_source.mode": "模式:",
- "value_source.mode.hint": "RMS 测量平均音量。峰值跟踪最响的时刻。节拍在节奏上触发。",
- "value_source.mode.rms": "RMS(音量)",
- "value_source.mode.peak": "峰值",
- "value_source.mode.beat": "节拍",
- "value_source.mode.rms.desc": "平均音量水平",
- "value_source.mode.peak.desc": "最响时刻追踪",
- "value_source.mode.beat.desc": "节奏脉冲检测",
- "value_source.auto_gain": "自动增益:",
- "value_source.auto_gain.hint": "自动归一化音频电平,使输出使用完整范围,无论输入音量大小",
- "value_source.auto_gain.enable": "启用自动增益",
- "value_source.sensitivity": "灵敏度:",
- "value_source.sensitivity.hint": "音频信号的增益倍数(越高反应越灵敏)",
- "value_source.scene_sensitivity.hint": "亮度信号的增益倍数(越高对亮度变化越敏感)",
- "value_source.smoothing": "平滑:",
- "value_source.smoothing.hint": "时间平滑(0 = 即时响应,1 = 非常平滑/缓慢)",
- "value_source.audio_min_value": "最小值:",
- "value_source.audio_min_value.hint": "音频静默时的输出(例如 0.3 = 30% 亮度下限)",
- "value_source.audio_max_value": "最大值:",
- "value_source.audio_max_value.hint": "最大音频电平时的输出",
- "value_source.schedule": "计划:",
- "value_source.schedule.hint": "定义至少 2 个时间点。亮度在各点之间线性插值,午夜循环。",
- "value_source.schedule.add": "+ 添加时间点",
- "value_source.schedule.points": "个时间点",
- "value_source.picture_source": "图片源:",
- "value_source.picture_source.hint": "将分析其帧以获取平均亮度的图片源。",
- "value_source.scene_behavior": "行为:",
- "value_source.scene_behavior.hint": "互补:暗场景 = 高亮度(适合环境背光)。匹配:亮场景 = 高亮度。",
- "value_source.scene_behavior.complement": "互补(暗 → 亮)",
- "value_source.scene_behavior.match": "匹配(亮 → 亮)",
- "value_source.adaptive_min_value": "最小值:",
- "value_source.adaptive_min_value.hint": "最小输出亮度",
- "value_source.adaptive_max_value": "最大值:",
- "value_source.adaptive_max_value.hint": "最大输出亮度",
- "value_source.error.schedule_min": "计划至少需要 2 个时间点",
- "value_source.description": "描述(可选):",
- "value_source.description.placeholder": "描述此值源...",
- "value_source.description.hint": "关于此值源的可选说明",
- "value_source.created": "值源已创建",
- "value_source.updated": "值源已更新",
- "value_source.deleted": "值源已删除",
- "value_source.delete.confirm": "确定要删除此值源吗?",
- "value_source.error.name_required": "请输入名称",
- "value_source.test": "测试",
- "value_source.test.title": "测试值源",
- "value_source.test.connecting": "连接中...",
- "value_source.test.error": "连接失败",
- "value_source.test.current": "当前",
- "value_source.test.min": "最小",
- "value_source.test.max": "最大",
- "test.frames": "帧数",
- "test.fps": "帧率",
- "test.avg_capture": "平均",
- "targets.brightness_vs": "亮度源:",
- "targets.brightness_vs.hint": "可选的值源,每帧动态控制亮度(覆盖设备亮度)",
- "targets.brightness_vs.none": "无(设备亮度)",
- "targets.min_brightness_threshold": "最低亮度阈值:",
- "targets.min_brightness_threshold.hint": "当有效输出亮度(像素亮度 × 设备/源亮度)低于此值时,LED完全关闭(0 = 禁用)",
- "targets.adaptive_fps": "自适应FPS:",
- "targets.adaptive_fps.hint": "当设备无响应时自动降低发送速率,稳定后逐步恢复。推荐用于信号较弱的WiFi设备。",
- "targets.protocol": "协议:",
- "targets.protocol.hint": "DDP通过快速UDP发送像素(推荐)。HTTP使用JSON API——较慢但可靠,限制约500个LED。",
- "targets.protocol.ddp": "DDP (UDP)",
- "targets.protocol.ddp.desc": "快速UDP数据包 - 推荐",
- "targets.protocol.http": "HTTP",
- "targets.protocol.http.desc": "JSON API - 较慢,≤500 LED",
- "targets.protocol.serial": "串口",
- "search.open": "搜索 (Ctrl+K)",
- "search.placeholder": "搜索实体... (Ctrl+K)",
- "search.loading": "加载中...",
- "search.no_results": "未找到结果",
- "search.group.devices": "设备",
- "search.group.targets": "LED 目标",
- "search.group.kc_targets": "关键颜色目标",
- "search.group.css": "色带源",
- "search.group.automations": "自动化",
- "search.group.streams": "图片流",
- "search.group.capture_templates": "采集模板",
- "search.group.pp_templates": "后处理模板",
- "search.group.pattern_templates": "图案模板",
- "search.group.audio": "音频源",
- "search.group.value": "值源",
- "search.group.scenes": "场景预设",
- "search.group.cspt": "色带处理模板",
- "search.group.sync_clocks": "同步时钟",
- "search.group.actions": "操作",
- "search.action.start": "启动",
- "search.action.stop": "停止",
- "search.action.activate": "激活",
- "search.action.enable": "启用",
- "search.action.disable": "禁用",
- "settings.backup.label": "备份配置",
- "settings.backup.hint": "将所有配置(设备、目标、流、模板、自动化)下载为单个 JSON 文件。",
- "settings.backup.button": "下载备份",
- "settings.backup.success": "备份下载成功",
- "settings.backup.error": "备份下载失败",
- "settings.restore.label": "恢复配置",
- "settings.restore.hint": "上传之前下载的备份文件以替换所有配置。服务器将自动重启。",
- "settings.restore.button": "从备份恢复",
- "settings.restore.confirm": "这将替换所有配置并重启服务器。确定继续吗?",
- "settings.restore.success": "配置已恢复",
- "settings.restore.error": "恢复失败",
- "settings.restore.restarting": "服务器正在重启...",
- "settings.restore.restart_timeout": "服务器未响应。请手动刷新页面。",
- "settings.restart_server": "重启服务器",
- "settings.restart_confirm": "重启服务器?活跃的目标将被停止。",
- "settings.restarting": "正在重启服务器...",
- "settings.button.close": "关闭",
- "settings.log_level.label": "日志级别",
- "settings.log_level.hint": "实时更改服务器日志详细程度。DEBUG 显示最多细节;CRITICAL 仅显示致命错误。",
- "settings.log_level.save": "应用",
- "settings.log_level.saved": "日志级别已更改",
- "settings.log_level.save_error": "更改日志级别失败",
- "settings.log_level.desc.debug": "详细开发输出",
- "settings.log_level.desc.info": "正常运行消息",
- "settings.log_level.desc.warning": "潜在问题",
- "settings.log_level.desc.error": "仅显示错误",
- "settings.log_level.desc.critical": "仅显示致命错误",
- "settings.auto_backup.label": "自动备份",
- "settings.auto_backup.hint": "自动定期创建所有配置的备份。当达到最大数量时,旧备份会被自动清理。",
- "settings.auto_backup.enable": "启用自动备份",
- "settings.auto_backup.interval_label": "间隔",
- "settings.auto_backup.max_label": "最大备份数",
- "settings.auto_backup.save": "保存设置",
- "settings.auto_backup.saved": "自动备份设置已保存",
- "settings.auto_backup.save_error": "保存自动备份设置失败",
- "settings.auto_backup.last_backup": "上次备份",
- "settings.auto_backup.never": "从未",
- "settings.saved_backups.label": "已保存的备份",
- "settings.saved_backups.hint": "存储在服务器上的自动备份文件。下载到本地保存,或删除以释放空间。",
- "settings.saved_backups.empty": "没有已保存的备份",
- "settings.saved_backups.restore": "恢复",
- "settings.saved_backups.download": "下载",
- "settings.saved_backups.delete": "删除",
- "settings.saved_backups.delete_confirm": "删除此备份文件?",
- "settings.saved_backups.delete_error": "删除备份失败",
- "settings.saved_backups.type.auto": "自动",
- "settings.saved_backups.type.manual": "手动",
- "settings.mqtt.label": "MQTT",
- "settings.mqtt.hint": "配置 MQTT 代理连接,用于自动化条件和触发器。",
- "settings.mqtt.enabled": "启用 MQTT",
- "settings.mqtt.host_label": "代理主机",
- "settings.mqtt.port_label": "端口",
- "settings.mqtt.username_label": "用户名",
- "settings.mqtt.password_label": "密码",
- "settings.mqtt.password_set_hint": "已设置密码 — 留空以保留",
- "settings.mqtt.client_id_label": "客户端 ID",
- "settings.mqtt.base_topic_label": "基础主题",
- "settings.mqtt.save": "保存 MQTT 设置",
- "settings.mqtt.saved": "MQTT 设置已保存",
- "settings.mqtt.save_error": "保存 MQTT 设置失败",
- "settings.mqtt.error_host_required": "代理主机不能为空",
- "settings.logs.label": "服务器日志",
- "settings.logs.hint": "实时查看服务器日志。使用过滤器显示所需的日志级别。",
- "settings.logs.connect": "连接",
- "settings.logs.disconnect": "断开",
- "settings.logs.clear": "清除",
- "settings.logs.error": "日志查看器连接失败",
- "settings.logs.filter.all": "所有级别",
- "settings.logs.filter.info": "Info+",
- "settings.logs.filter.warning": "Warning+",
- "settings.logs.filter.error": "仅错误",
- "settings.logs.filter.all_desc": "显示所有日志消息",
- "settings.logs.filter.info_desc": "Info、警告和错误",
- "settings.logs.filter.warning_desc": "仅警告和错误",
- "settings.logs.filter.error_desc": "仅错误",
- "device.error.power_off_failed": "关闭设备失败",
- "device.removed": "设备已移除",
- "device.error.remove_failed": "移除设备失败",
- "device.error.settings_load_failed": "加载设备设置失败",
- "device.error.brightness": "更新亮度失败",
- "device.error.required": "请填写所有字段",
- "device.error.update": "更新设备失败",
- "device.error.save": "保存设置失败",
- "device.error.clone_failed": "克隆设备失败",
- "device_discovery.error.fill_all_fields": "请填写所有字段",
- "device_discovery.added": "设备添加成功",
- "device_discovery.error.add_failed": "添加设备失败",
- "calibration.error.load_failed": "加载校准失败",
- "calibration.error.css_load_failed": "加载色带源失败",
- "calibration.error.test_toggle_failed": "切换测试边缘失败",
- "calibration.saved": "校准已保存",
- "calibration.error.save_failed": "保存校准失败",
- "calibration.error.led_count_mismatch": "LED总数必须等于设备LED数量",
- "calibration.error.led_count_exceeded": "校准的LED超过了LED总数",
- "calibration.mode.simple": "简单",
- "calibration.mode.advanced": "高级",
- "calibration.switch_to_advanced": "切换到高级模式",
- "calibration.advanced.title": "高级校准",
- "calibration.advanced.switch_to_simple": "切换到简单模式",
- "calibration.advanced.lines_title": "线段",
- "calibration.advanced.canvas_hint": "拖动显示器重新排列。点击边缘选择线段。滚动缩放,拖动空白区域平移。",
- "calibration.advanced.reset_view": "重置视图",
- "calibration.advanced.line_properties": "线段属性",
- "calibration.advanced.picture_source": "来源:",
- "calibration.advanced.picture_source.hint": "此线段采样的图片来源(显示器)",
- "calibration.advanced.edge": "边缘:",
- "calibration.advanced.edge.hint": "从屏幕哪条边缘采样像素",
- "calibration.advanced.led_count": "LED数:",
- "calibration.advanced.led_count.hint": "映射到此线段的LED数量",
- "calibration.advanced.span_start": "起始位置:",
- "calibration.advanced.span_start.hint": "沿边缘开始采样的位置(0 = 起点,1 = 终点)。用于仅覆盖边缘的一部分。",
- "calibration.advanced.span_end": "结束位置:",
- "calibration.advanced.span_end.hint": "沿边缘结束采样的位置(0 = 起点,1 = 终点)。与起始位置一起定义活动区域。",
- "calibration.advanced.border_width": "深度(像素):",
- "calibration.advanced.border_width.hint": "从边缘向内采样多少像素。较大的值会捕获更多屏幕内部区域。",
- "calibration.advanced.reverse": "反转",
- "calibration.advanced.no_lines_warning": "请至少添加一条线段",
- "dashboard.error.automation_toggle_failed": "切换自动化失败",
- "dashboard.error.start_failed": "启动处理失败",
- "dashboard.error.stop_failed": "停止处理失败",
- "dashboard.error.stop_all": "停止所有目标失败",
- "target.error.editor_open_failed": "打开目标编辑器失败",
- "target.error.start_failed": "启动目标失败",
- "target.error.stop_failed": "停止目标失败",
- "target.error.clone_failed": "克隆目标失败",
- "target.error.delete_failed": "删除目标失败",
- "targets.stop_all.button": "全部停止",
- "targets.stop_all.none_running": "当前没有运行中的目标",
- "targets.stop_all.stopped": "已停止 {count} 个目标",
- "targets.stop_all.error": "停止目标失败",
- "audio_source.error.load": "加载音频源失败",
- "audio_template.error.clone_failed": "克隆音频模板失败",
- "value_source.error.load": "加载数值源失败",
- "color_strip.error.editor_open_failed": "打开色带编辑器失败",
- "color_strip.error.clone_failed": "克隆色带源失败",
- "color_strip.error.delete_failed": "删除色带源失败",
- "pattern.error.editor_open_failed": "打开图案模板编辑器失败",
- "pattern.error.clone_failed": "克隆图案模板失败",
- "pattern.error.delete_failed": "删除图案模板失败",
- "pattern.error.capture_bg_failed": "捕获背景失败",
- "stream.error.clone_picture_failed": "克隆图片源失败",
- "stream.error.clone_capture_failed": "克隆捕获模板失败",
- "stream.error.clone_pp_failed": "克隆后处理模板失败",
- "kc_target.error.editor_open_failed": "打开关键颜色编辑器失败",
- "kc_target.error.clone_failed": "克隆关键颜色目标失败",
- "kc_target.error.delete_failed": "删除关键颜色目标失败",
- "theme.switched.dark": "已切换到深色主题",
- "theme.switched.light": "已切换到浅色主题",
- "accent.color.updated": "强调色已更新",
- "search.footer": "↑↓ 导航 · Enter 选择 · Esc 关闭",
- "sync_clock.group.title": "同步时钟",
- "sync_clock.add": "添加同步时钟",
- "sync_clock.edit": "编辑同步时钟",
- "sync_clock.name": "名称:",
- "sync_clock.name.placeholder": "主动画时钟",
- "sync_clock.name.hint": "此同步时钟的描述性名称",
- "sync_clock.speed": "速度:",
- "sync_clock.speed.hint": "所有关联源的动画速度倍率。1.0 = 正常,2.0 = 双倍,0.5 = 半速。",
- "sync_clock.description": "描述(可选):",
- "sync_clock.description.placeholder": "可选描述",
- "sync_clock.description.hint": "关于此时钟用途的可选备注",
- "sync_clock.status.running": "运行中",
- "sync_clock.status.paused": "已暂停",
- "sync_clock.action.pause": "暂停",
- "sync_clock.action.resume": "恢复",
- "sync_clock.action.reset": "重置",
- "sync_clock.error.name_required": "时钟名称为必填项",
- "sync_clock.error.load": "加载同步时钟失败",
- "sync_clock.created": "同步时钟已创建",
- "sync_clock.updated": "同步时钟已更新",
- "sync_clock.deleted": "同步时钟已删除",
- "sync_clock.paused": "时钟已暂停",
- "sync_clock.resumed": "时钟已恢复",
- "sync_clock.reset_done": "时钟已重置为零",
- "sync_clock.delete.confirm": "删除此同步时钟?关联的源将失去同步并以默认速度运行。",
- "sync_clock.elapsed": "已用时间",
- "color_strip.clock": "同步时钟:",
- "color_strip.clock.hint": "关联同步时钟以在多个源之间同步动画。速度在时钟上控制。",
- "graph.title": "图表",
- "graph.fit_all": "显示所有节点",
- "graph.zoom_in": "放大",
- "graph.zoom_out": "缩小",
- "graph.search": "搜索节点",
- "graph.search_placeholder": "搜索实体...",
- "graph.legend": "图例",
- "graph.minimap": "小地图",
- "graph.relayout": "重新布局",
- "graph.empty": "暂无实体",
- "graph.empty.hint": "创建设备、源和目标后即可在此查看。",
- "graph.disconnect": "断开连接",
- "graph.connection_updated": "连接已更新",
- "graph.connection_failed": "更新连接失败",
- "graph.connection_removed": "连接已移除",
- "graph.disconnect_failed": "断开连接失败",
- "graph.relayout_confirm": "重置所有手动节点位置并重新布局图表?",
- "graph.fullscreen": "切换全屏",
- "graph.add_entity": "添加实体",
- "graph.color_picker": "节点颜色",
- "graph.filter": "筛选节点",
- "graph.filter_placeholder": "按名称筛选...",
- "graph.filter_clear": "清除筛选",
- "graph.filter_running": "运行中",
- "graph.filter_stopped": "已停止",
- "graph.filter_types": "类型",
- "graph.filter_group.capture": "捕获",
- "graph.filter_group.strip": "色带",
- "graph.filter_group.audio": "音频",
- "graph.filter_group.targets": "目标",
- "graph.filter_group.other": "其他",
- "graph.bulk_delete_confirm": "删除 {count} 个选中的实体?",
- "graph.nothing_to_undo": "没有可撤销的操作",
- "graph.nothing_to_redo": "没有可重做的操作",
- "graph.help_title": "键盘快捷键",
- "graph.help.search": "搜索",
- "graph.help.filter": "筛选",
- "graph.help.add": "添加实体",
- "graph.help.shortcuts": "快捷键",
- "graph.help.delete": "删除 / 断开",
- "graph.help.select_all": "全选",
- "graph.help.undo": "撤销",
- "graph.help.redo": "重做",
- "graph.help.fullscreen": "全屏",
- "graph.help.deselect": "取消选择",
- "graph.help.navigate": "节点导航",
- "graph.help.click": "单击",
- "graph.help.click_desc": "选择节点",
- "graph.help.dblclick": "双击",
- "graph.help.dblclick_desc": "缩放到节点",
- "graph.help.shift_click": "Shift+单击",
- "graph.help.shift_click_desc": "多选",
- "graph.help.shift_drag": "Shift+拖拽",
- "graph.help.shift_drag_desc": "框选",
- "graph.help.drag_node": "拖拽节点",
- "graph.help.drag_node_desc": "重新定位",
- "graph.help.drag_port": "拖拽端口",
- "graph.help.drag_port_desc": "连接实体",
- "graph.help.right_click": "右键边线",
- "graph.help.right_click_desc": "断开连接",
- "graph.tooltip.fps": "帧率",
- "graph.tooltip.errors": "错误",
- "graph.tooltip.uptime": "运行时间",
- "automation.enabled": "自动化已启用",
- "automation.disabled": "自动化已禁用",
- "scene_preset.activated": "预设已激活",
- "scene_preset.used_by": "被 %d 个自动化使用",
- "settings.api_keys.label": "API 密钥",
- "settings.api_keys.hint": "API 密钥在服务器配置文件 (config.yaml) 中定义。编辑文件并重启服务器以应用更改。",
- "settings.api_keys.empty": "未配置 API 密钥",
- "settings.api_keys.load_error": "加载 API 密钥失败",
- "settings.partial.label": "部分导出 / 导入",
- "settings.partial.hint": "导出或导入单个实体类型。导入会替换或合并现有数据并重启服务器。",
- "settings.partial.store.devices": "设备",
- "settings.partial.store.output_targets": "LED 目标",
- "settings.partial.store.color_strip_sources": "色带",
- "settings.partial.store.picture_sources": "图像源",
- "settings.partial.store.audio_sources": "音频源",
- "settings.partial.store.audio_templates": "音频模板",
- "settings.partial.store.capture_templates": "捕获模板",
- "settings.partial.store.postprocessing_templates": "后处理模板",
- "settings.partial.store.color_strip_processing_templates": "CSS 处理模板",
- "settings.partial.store.pattern_templates": "图案模板",
- "settings.partial.store.value_sources": "值源",
- "settings.partial.store.sync_clocks": "同步时钟",
- "settings.partial.store.automations": "自动化",
- "settings.partial.store.scene_presets": "场景预设",
- "settings.partial.export_button": "导出",
- "settings.partial.import_button": "从文件导入",
- "settings.partial.merge_label": "合并(添加/覆盖,保留现有)",
- "settings.partial.export_success": "导出成功",
- "settings.partial.export_error": "导出失败",
- "settings.partial.import_success": "导入成功",
- "settings.partial.import_error": "导入失败",
- "settings.partial.import_confirm_replace": "这将替换所有 {store} 数据并重启服务器。继续吗?",
- "settings.partial.import_confirm_merge": "这将合并 {store} 数据并重启服务器。继续吗?",
- "section.empty.devices": "暂无设备。点击 + 添加。",
- "section.empty.targets": "暂无 LED 目标。点击 + 添加。",
- "section.empty.kc_targets": "暂无键色目标。点击 + 添加。",
- "section.empty.pattern_templates": "暂无图案模板。点击 + 添加。",
- "section.empty.picture_sources": "暂无源。点击 + 添加。",
- "section.empty.capture_templates": "暂无捕获模板。点击 + 添加。",
- "section.empty.pp_templates": "暂无后处理模板。点击 + 添加。",
- "section.empty.audio_sources": "暂无音频源。点击 + 添加。",
- "section.empty.audio_templates": "暂无音频模板。点击 + 添加。",
- "section.empty.color_strips": "暂无色带。点击 + 添加。",
- "section.empty.value_sources": "暂无值源。点击 + 添加。",
- "section.empty.sync_clocks": "暂无同步时钟。点击 + 添加。",
- "section.empty.cspt": "暂无 CSS 处理模板。点击 + 添加。",
- "section.empty.automations": "暂无自动化。点击 + 添加。",
- "section.empty.scenes": "暂无场景预设。点击 + 添加。",
-
- "bulk.select": "选择",
- "bulk.cancel": "取消",
- "bulk.selected_count.one": "已选 {count} 项",
- "bulk.selected_count.other": "已选 {count} 项",
- "bulk.select_all": "全选",
- "bulk.deselect_all": "取消全选",
- "bulk.delete": "删除",
- "bulk.start": "启动",
- "bulk.stop": "停止",
- "bulk.enable": "启用",
- "bulk.disable": "禁用",
- "bulk.confirm_delete.one": "删除 {count} 项?",
- "bulk.confirm_delete.other": "删除 {count} 项?"
-}
+ "app.title": "LED Grab",
+ "app.version": "版本:",
+ "app.api_docs": "API 文档",
+ "app.connection_lost": "服务器不可达",
+ "app.connection_retrying": "正在尝试重新连接…",
+ "demo.badge": "演示",
+ "demo.banner": "您正处于演示模式 — 所有设备和数据均为虚拟。未使用任何真实硬件。",
+ "theme.toggle": "切换主题",
+ "bg.anim.toggle": "切换动态背景",
+ "accent.title": "主题色",
+ "accent.custom": "自定义",
+ "accent.reset": "重置",
+ "locale.change": "切换语言",
+ "auth.login": "登录",
+ "auth.logout": "退出",
+ "auth.authenticated": "● 已认证",
+ "auth.title": "登录 LED Grab",
+ "auth.message": "请输入 API 密钥以进行身份验证并访问 LED Grab。",
+ "auth.label": "API 密钥:",
+ "auth.placeholder": "输入您的 API 密钥...",
+ "auth.hint": "API 密钥将安全存储在浏览器的本地存储中。",
+ "auth.button.cancel": "取消",
+ "auth.button.login": "登录",
+ "auth.error.required": "请输入 API 密钥",
+ "auth.success": "登录成功!",
+ "auth.logout.confirm": "确定要退出登录吗?",
+ "auth.logout.success": "已成功退出",
+ "auth.please_login": "请先登录",
+ "auth.session_expired": "会话已过期或 API 密钥无效,请重新登录。",
+ "auth.toggle_password": "切换密码可见性",
+ "auth.prompt_enter": "Enter your API key:",
+ "auth.prompt_update": "Current API key is set. Enter new key to update or leave blank to remove:",
+ "api_key.login": "登录",
+ "displays.title": "可用显示器",
+ "displays.layout": "显示器",
+ "displays.information": "显示器信息",
+ "displays.legend.primary": "主显示器",
+ "displays.legend.secondary": "副显示器",
+ "displays.badge.primary": "主",
+ "displays.badge.secondary": "副",
+ "displays.resolution": "分辨率:",
+ "displays.refresh_rate": "刷新率:",
+ "displays.position": "位置:",
+ "displays.index": "显示器序号:",
+ "displays.loading": "正在加载显示器...",
+ "displays.none": "没有可用的显示器",
+ "displays.failed": "加载显示器失败",
+ "displays.picker.title": "选择显示器",
+ "displays.picker.title.device": "选择设备",
+ "displays.picker.select": "选择显示器...",
+ "displays.picker.click_to_select": "点击选择此显示器",
+ "displays.picker.adb_connect": "连接 ADB 设备",
+ "displays.picker.adb_connect.placeholder": "IP 地址(例如 192.168.2.201)",
+ "displays.picker.adb_connect.button": "连接",
+ "displays.picker.adb_connect.success": "设备已连接",
+ "displays.picker.adb_connect.error": "连接设备失败",
+ "displays.picker.adb_disconnect": "断开连接",
+ "displays.picker.no_android": "未找到 Android 设备。请通过 USB 连接或在上方输入 IP 地址。",
+ "templates.title": "引擎模板",
+ "templates.description": "采集模板定义屏幕的采集方式。每个模板使用特定的采集引擎(MSS、DXcam、WGC)及自定义设置。将模板分配给设备以获得最佳性能。",
+ "templates.loading": "正在加载模板...",
+ "templates.empty": "尚未配置采集模板",
+ "templates.add": "添加引擎模板",
+ "templates.edit": "编辑引擎模板",
+ "templates.name": "模板名称:",
+ "templates.name.placeholder": "我的自定义模板",
+ "templates.description.label": "描述(可选):",
+ "templates.description.placeholder": "描述此模板...",
+ "templates.engine": "采集引擎:",
+ "templates.engine.hint": "选择要使用的屏幕采集技术",
+ "templates.engine.select": "选择引擎...",
+ "templates.engine.unavailable": "不可用",
+ "templates.engine.unavailable.hint": "此引擎在您的系统上不可用",
+ "templates.engine.mss.desc": "跨平台,纯Python",
+ "templates.engine.dxcam.desc": "DirectX,低延迟",
+ "templates.engine.bettercam.desc": "DirectX,高性能",
+ "templates.engine.camera.desc": "USB/IP摄像头捕获",
+ "templates.engine.scrcpy.desc": "Android屏幕镜像",
+ "templates.engine.wgc.desc": "Windows图形捕获",
+ "templates.config": "配置",
+ "templates.config.show": "显示配置",
+ "templates.config.none": "无额外配置",
+ "templates.config.default": "默认",
+ "templates.config.camera_backend.auto": "自动检测最佳后端",
+ "templates.config.camera_backend.dshow": "Windows DirectShow",
+ "templates.config.camera_backend.msmf": "Windows Media Foundation",
+ "templates.config.camera_backend.v4l2": "Linux Video4Linux2",
+ "templates.created": "模板创建成功",
+ "templates.updated": "模板更新成功",
+ "templates.deleted": "模板删除成功",
+ "templates.delete.confirm": "确定要删除此模板吗?",
+ "templates.error.load": "加载模板失败",
+ "templates.error.engines": "加载引擎失败",
+ "templates.error.required": "请填写所有必填项",
+ "templates.error.delete": "删除模板失败",
+ "templates.test.title": "测试采集",
+ "templates.test.description": "保存前测试此模板,查看采集预览和性能指标。",
+ "templates.test.display": "显示器:",
+ "templates.test.display.select": "选择显示器...",
+ "templates.test.duration": "采集时长(秒):",
+ "templates.test.border_width": "边框宽度(像素):",
+ "templates.test.run": "运行",
+ "templates.test.running": "正在运行测试...",
+ "templates.test.results.preview": "全幅采集预览",
+ "templates.test.results.borders": "边框提取",
+ "templates.test.results.top": "上",
+ "templates.test.results.right": "右",
+ "templates.test.results.bottom": "下",
+ "templates.test.results.left": "左",
+ "templates.test.results.performance": "性能",
+ "templates.test.results.capture_time": "采集",
+ "templates.test.results.extraction_time": "提取",
+ "templates.test.results.total_time": "总计",
+ "templates.test.results.max_fps": "最大 FPS",
+ "templates.test.results.duration": "时长",
+ "templates.test.results.frame_count": "帧数",
+ "templates.test.results.actual_fps": "实际 FPS",
+ "templates.test.results.avg_capture_time": "平均采集",
+ "templates.test.results.resolution": "分辨率:",
+ "templates.test.error.no_engine": "请选择采集引擎",
+ "templates.test.error.no_display": "请选择显示器",
+ "templates.test.error.failed": "测试失败",
+ "devices.title": "设备",
+ "device.select_type": "选择设备类型",
+ "devices.add": "添加新设备",
+ "devices.loading": "正在加载设备...",
+ "devices.none": "尚未配置设备",
+ "devices.failed": "加载设备失败",
+ "devices.wled_config": "WLED 配置:",
+ "devices.wled_note": "使用以下方式配置您的 WLED 设备(效果、分段、颜色顺序、功率限制等):",
+ "devices.wled_link": "官方 WLED 应用",
+ "devices.wled_note_or": "或内置的",
+ "devices.wled_webui_link": "WLED Web UI",
+ "devices.wled_note_webui": "(在浏览器中打开设备 IP 地址)。",
+ "devices.wled_note2": "此控制器发送像素颜色数据并控制每个设备的亮度。",
+ "device.scan": "自动发现",
+ "device.scan.empty": "未找到设备",
+ "device.scan.error": "网络扫描失败",
+ "device.scan.already_added": "已添加",
+ "device.scan.selected": "设备已选择",
+ "device.type": "设备类型:",
+ "device.type.hint": "选择 LED 控制器的类型",
+ "device.type.wled": "WLED",
+ "device.type.wled.desc": "通过HTTP/UDP控制的WiFi LED",
+ "device.type.adalight": "Adalight",
+ "device.type.adalight.desc": "Arduino串口LED协议",
+ "device.type.ambiled": "AmbiLED",
+ "device.type.ambiled.desc": "AmbiLED串口协议",
+ "device.type.mqtt": "MQTT",
+ "device.type.mqtt.desc": "通过MQTT代理发布LED数据",
+ "device.type.ws": "WebSocket",
+ "device.type.ws.desc": "通过WebSocket流式传输LED数据",
+ "device.type.openrgb": "OpenRGB",
+ "device.type.openrgb.desc": "通过OpenRGB控制RGB外设",
+ "device.type.dmx": "DMX",
+ "device.type.dmx.desc": "Art-Net / sACN (E1.31) 舞台灯光",
+ "device.type.mock": "Mock",
+ "device.type.mock.desc": "用于测试的虚拟设备",
+ "device.type.espnow": "ESP-NOW",
+ "device.type.espnow.desc": "Ultra-low-latency via ESP32 gateway",
+ "device.type.hue": "Philips Hue",
+ "device.type.hue.desc": "Hue Entertainment API streaming",
+ "device.type.usbhid": "USB HID",
+ "device.type.usbhid.desc": "USB RGB peripherals (keyboards, mice)",
+ "device.type.spi": "SPI Direct",
+ "device.type.spi.desc": "Raspberry Pi GPIO/SPI LED strips",
+ "device.type.chroma": "Razer Chroma",
+ "device.type.chroma.desc": "Razer peripherals via Chroma SDK",
+ "device.type.gamesense": "SteelSeries",
+ "device.type.gamesense.desc": "SteelSeries peripherals via GameSense",
+ "device.chroma.device_type": "Peripheral Type:",
+ "device.chroma.device_type.hint": "Which Razer peripheral to control via Chroma SDK",
+ "device.gamesense.device_type": "Peripheral Type:",
+ "device.gamesense.device_type.hint": "Which SteelSeries peripheral to control via GameSense",
+ "device.espnow.peer_mac": "Peer MAC:",
+ "device.espnow.peer_mac.hint": "MAC address of the remote ESP32 receiver (e.g. AA:BB:CC:DD:EE:FF)",
+ "device.espnow.channel": "WiFi Channel:",
+ "device.espnow.channel.hint": "WiFi channel (1-14). Must match the receiver's channel.",
+ "device.hue.url": "Bridge IP:",
+ "device.hue.url.hint": "IP address of your Hue bridge",
+ "device.hue.username": "Bridge Username:",
+ "device.hue.username.hint": "Hue bridge application key from pairing",
+ "device.hue.client_key": "Client Key:",
+ "device.hue.client_key.hint": "Entertainment API client key (hex string from pairing)",
+ "device.hue.group_id": "Entertainment Group:",
+ "device.hue.group_id.hint": "Entertainment configuration ID from your Hue bridge",
+ "device.usbhid.url": "VID:PID:",
+ "device.usbhid.url.hint": "USB Vendor:Product ID in hex (e.g. 1532:0084)",
+ "device.spi.url": "GPIO/SPI Path:",
+ "device.spi.url.hint": "GPIO pin or SPI device path (e.g. spi://gpio:18)",
+ "device.spi.speed": "SPI Speed (Hz):",
+ "device.spi.speed.hint": "SPI clock speed. 800000 Hz for WS2812, 2400000 Hz for APA102.",
+ "device.spi.led_type": "LED Chipset:",
+ "device.spi.led_type.hint": "Type of addressable LED strip connected to the GPIO/SPI pin",
+ "device.spi.led_type.ws2812b.desc": "Most common, 800 KHz data, 3-wire RGB",
+ "device.spi.led_type.ws2812.desc": "Original WS2812, 800 KHz, 3-wire RGB",
+ "device.spi.led_type.ws2811.desc": "External driver IC, 400 KHz, 12V strips",
+ "device.spi.led_type.sk6812.desc": "Samsung LED, 800 KHz, 3-wire RGB",
+ "device.spi.led_type.sk6812_rgbw.desc": "SK6812 with dedicated white channel",
+ "device.gamesense.peripheral.keyboard": "Keyboard",
+ "device.gamesense.peripheral.keyboard.desc": "Per-key RGB illumination",
+ "device.gamesense.peripheral.mouse": "Mouse",
+ "device.gamesense.peripheral.mouse.desc": "Mouse RGB zones",
+ "device.gamesense.peripheral.headset": "Headset",
+ "device.gamesense.peripheral.headset.desc": "Headset earcup lighting",
+ "device.gamesense.peripheral.mousepad": "Mousepad",
+ "device.gamesense.peripheral.mousepad.desc": "Mousepad edge lighting zones",
+ "device.gamesense.peripheral.indicator": "Indicator",
+ "device.gamesense.peripheral.indicator.desc": "OLED/LED status indicator",
+ "device.dmx_protocol": "DMX 协议:",
+ "device.dmx_protocol.hint": "Art-Net 使用 UDP 端口 6454,sACN (E1.31) 使用 UDP 端口 5568",
+ "device.dmx_protocol.artnet.desc": "UDP 单播,端口 6454",
+ "device.dmx_protocol.sacn.desc": "组播/单播,端口 5568",
+ "device.dmx_start_universe": "起始 Universe:",
+ "device.dmx_start_universe.hint": "第一个 DMX universe (0-32767)。超过 170 个 LED 时自动使用多个 universe。",
+ "device.dmx_start_channel": "起始通道:",
+ "device.dmx_start_channel.hint": "universe 中的第一个 DMX 通道 (1-512)",
+ "device.dmx.url": "IP 地址:",
+ "device.dmx.url.hint": "DMX 节点的 IP 地址(例如 192.168.1.50)",
+ "device.dmx.url.placeholder": "192.168.1.50",
+ "device.serial_port": "串口:",
+ "device.serial_port.hint": "选择 Adalight 设备的 COM 端口",
+ "device.serial_port.none": "未找到串口",
+ "device.serial_port.select": "选择端口...",
+ "device.led_count_manual.hint": "灯带上的 LED 数量(必须与 Arduino 程序匹配)",
+ "device.baud_rate": "波特率:",
+ "device.baud_rate.hint": "串口通信速率。越高 FPS 越高,但需要与 Arduino 程序匹配。",
+ "device.led_type": "LED 类型:",
+ "device.led_type.hint": "RGB(3通道)或 RGBW(4通道,带独立白色)",
+ "device.send_latency": "发送延迟(毫秒):",
+ "device.send_latency.hint": "每帧模拟网络/串口延迟(毫秒)",
+ "device.css_processing_template": "色带处理模板:",
+ "device.css_processing_template.hint": "应用于此设备所有色带输出的默认处理模板",
+ "device.mqtt_topic": "MQTT 主题:",
+ "device.mqtt_topic.hint": "用于发布像素数据的 MQTT 主题路径(例如 mqtt://ledgrab/device/name)",
+ "device.mqtt_topic.placeholder": "mqtt://ledgrab/device/客厅",
+ "device.ws_url": "连接 URL:",
+ "device.ws_url.hint": "客户端连接并接收 LED 数据的 WebSocket URL",
+ "device.openrgb.url": "OpenRGB URL:",
+ "device.openrgb.url.hint": "OpenRGB 服务器地址(例如 openrgb://localhost:6742/0)",
+ "device.openrgb.zone": "区域:",
+ "device.openrgb.zone.hint": "选择要控制的 LED 区域(全部不选则控制所有区域)",
+ "device.openrgb.zone.loading": "加载区域中…",
+ "device.openrgb.zone.error": "加载区域失败",
+ "device.openrgb.mode": "区域模式:",
+ "device.openrgb.mode.hint": "合并模式将所有区域作为一条连续 LED 灯带。独立模式让每个区域独立渲染完整效果。",
+ "device.openrgb.mode.combined": "合并灯带",
+ "device.openrgb.mode.separate": "独立区域",
+ "device.openrgb.added_multiple": "已添加 {count} 个设备",
+ "device.url.hint": "设备的 IP 地址或主机名(例如 http://192.168.1.100)",
+ "device.name": "设备名称:",
+ "device.name.placeholder": "客厅电视",
+ "device.url": "地址:",
+ "device.url.placeholder": "http://192.168.1.100",
+ "device.led_count": "LED 数量:",
+ "device.led_count.hint": "设备中配置的 LED 数量",
+ "device.led_count.hint.auto": "从设备自动检测",
+ "device.button.add": "添加设备",
+ "device.button.start": "启动",
+ "device.button.stop": "停止",
+ "device.button.settings": "常规设置",
+ "device.button.capture_settings": "采集设置",
+ "device.button.calibrate": "校准",
+ "device.button.remove": "移除",
+ "device.button.webui": "打开设备 Web UI",
+ "device.button.power_off": "关闭",
+ "device.button.ping": "Ping 设备",
+ "device.ping.online": "在线 ({ms}ms)",
+ "device.ping.offline": "设备离线",
+ "device.ping.error": "Ping 失败",
+ "device.power.off_success": "设备已关闭",
+ "device.status.connected": "已连接",
+ "device.status.disconnected": "已断开",
+ "device.status.error": "错误",
+ "device.status.processing": "处理中",
+ "device.status.idle": "空闲",
+ "device.fps": "FPS:",
+ "device.display": "显示器:",
+ "device.remove.confirm": "确定要移除此设备吗?",
+ "device.added": "设备添加成功",
+ "device.removed": "设备已移除",
+ "device.started": "处理已启动",
+ "device.stopped": "处理已停止",
+ "device.metrics.actual_fps": "实际 FPS",
+ "device.metrics.current_fps": "当前 FPS",
+ "device.metrics.target_fps": "目标 FPS",
+ "device.metrics.potential_fps": "潜在 FPS",
+ "device.metrics.frames": "帧数",
+ "device.metrics.frames_skipped": "已跳过",
+ "device.metrics.keepalive": "心跳",
+ "device.metrics.errors": "错误",
+ "device.metrics.uptime": "运行时长",
+ "device.metrics.timing": "管线时序:",
+ "device.metrics.device_fps": "设备刷新率",
+ "device.health.online": "在线",
+ "device.health.offline": "离线",
+ "device.health.streaming_unreachable": "流传输期间不可达",
+ "device.health.checking": "检测中...",
+ "device.last_seen.label": "最近检测",
+ "device.last_seen.just_now": "刚刚",
+ "device.last_seen.seconds": "%d秒前",
+ "device.last_seen.minutes": "%d分钟前",
+ "device.last_seen.hours": "%d小时前",
+ "device.last_seen.days": "%d天前",
+ "device.tutorial.start": "开始教程",
+ "device.tip.metadata": "设备信息(LED 数量、类型、颜色通道)从设备自动检测",
+ "device.tip.brightness": "滑动调节设备亮度",
+ "device.tip.start": "启动或停止屏幕采集处理",
+ "device.tip.settings": "配置设备常规设置(名称、地址、健康检查)",
+ "device.tip.capture_settings": "配置采集设置(显示器、采集模板)",
+ "device.tip.calibrate": "校准 LED 位置、方向和覆盖范围",
+ "device.tip.webui": "打开设备内置的 Web 界面进行高级配置",
+ "device.tip.add": "点击此处添加新的 LED 设备",
+ "settings.title": "设置",
+ "settings.tab.general": "常规",
+ "settings.tab.backup": "备份",
+ "settings.tab.mqtt": "MQTT",
+ "settings.logs.open_viewer": "打开日志查看器",
+ "settings.external_url.label": "外部 URL",
+ "settings.external_url.hint": "设置后,此基础 URL 将用于 webhook 链接和其他用户可见的链接,代替自动检测的本地 IP。示例:https://myserver.example.com:8080",
+ "settings.external_url.placeholder": "https://myserver.example.com:8080",
+ "settings.external_url.save": "保存",
+ "settings.external_url.saved": "外部 URL 已保存",
+ "settings.external_url.save_error": "保存外部 URL 失败",
+ "settings.general.title": "常规设置",
+ "settings.capture.title": "采集设置",
+ "settings.capture.saved": "采集设置已更新",
+ "settings.capture.failed": "保存采集设置失败",
+ "settings.brightness": "亮度:",
+ "settings.brightness.hint": "此设备的全局亮度(0-100%)",
+ "settings.url.hint": "设备的 IP 地址或主机名",
+ "settings.display_index": "显示器:",
+ "settings.display_index.hint": "为此设备采集哪个屏幕",
+ "settings.fps": "目标 FPS:",
+ "settings.fps.hint": "目标帧率(10-90)",
+ "settings.capture_template": "引擎模板:",
+ "settings.capture_template.hint": "此设备的屏幕采集引擎和配置",
+ "settings.button.cancel": "取消",
+ "settings.health_interval": "健康检查间隔(秒):",
+ "settings.health_interval.hint": "检查设备状态的频率(5-600秒)",
+ "settings.auto_shutdown": "自动恢复:",
+ "settings.auto_shutdown.hint": "当目标停止或服务器关闭时恢复设备到空闲状态",
+ "settings.button.save": "保存更改",
+ "settings.saved": "设置保存成功",
+ "settings.failed": "保存设置失败",
+ "calibration.title": "LED 校准",
+ "calibration.tip.led_count": "输入每条边的 LED 数量",
+ "calibration.tip.start_corner": "点击角落设置起始位置",
+ "calibration.tip.direction": "切换灯带方向(顺时针/逆时针)",
+ "calibration.tip.offset": "设置 LED 偏移 — 从 LED 0 到起始角落的距离",
+ "calibration.tip.span": "拖动绿色条调整覆盖范围",
+ "calibration.tip.test": "点击边缘切换测试 LED",
+ "calibration.tip.overlay": "切换屏幕叠加层以查看显示器上的 LED 位置和编号",
+ "calibration.tip.toggle_inputs": "点击 LED 总数切换边缘输入",
+ "calibration.tip.border_width": "从屏幕边缘采样多少像素来确定 LED 颜色",
+ "calibration.tip.skip_leds_start": "跳过灯带起始端的 LED — 被跳过的 LED 保持关闭",
+ "calibration.tip.skip_leds_end": "跳过灯带末尾端的 LED — 被跳过的 LED 保持关闭",
+ "tour.welcome": "欢迎使用 LED Grab!快速导览将带您了解界面。使用方向键或按钮进行导航。",
+ "tour.dashboard": "仪表盘 — 实时查看运行中的目标、自动化和设备状态。",
+ "tour.targets": "目标 — 添加 WLED 设备,配置 LED 目标的捕获设置和校准。",
+ "tour.sources": "来源 — 管理捕获模板、图片来源、音频来源和色带。",
+ "tour.graph": "图表 — 所有实体及其连接的可视化概览。拖动端口进行连接,右键单击边线断开连接。",
+ "tour.automations": "自动化 — 通过时间、音频或数值条件自动切换场景。",
+ "tour.settings": "设置 — 备份和恢复配置,管理自动备份。",
+ "tour.api": "API 文档 — 基于 Swagger 的交互式 REST API 文档。",
+ "tour.search": "搜索 — 使用 Ctrl+K 快速查找并导航到任意实体。",
+ "tour.theme": "主题 — 在深色和浅色模式之间切换。",
+ "tour.accent": "主题色 — 自定义界面的强调颜色。",
+ "tour.language": "语言 — 选择您偏好的界面语言。",
+ "tour.restart": "重新开始导览",
+ "tour.dash.perf": "性能 — 实时 FPS 图表、延迟指标和轮询间隔控制。",
+ "tour.dash.running": "运行中的目标 — 实时流媒体指标和快速停止控制。",
+ "tour.dash.stopped": "已停止的目标 — 一键启动。",
+ "tour.dash.automations": "自动化 — 活动自动化状态和快速启用/禁用切换。",
+ "tour.tgt.led_tab": "LED 标签 — 标准 LED 灯带目标,包含设备和色带配置。",
+ "tour.tgt.devices": "设备 — 在网络中发现的 LED 控制器。",
+ "tour.tgt.css": "色带 — 定义屏幕区域如何映射到 LED 段。",
+ "tour.tgt.targets": "LED 目标 — 将设备、色带和捕获源组合进行流式传输。",
+ "tour.tgt.kc_tab": "Key Colors — 使用颜色匹配代替像素映射的替代目标类型。",
+ "tour.src.raw": "原始 — 来自显示器的实时屏幕捕获源。",
+ "tour.src.templates": "捕获模板 — 可复用的捕获配置(分辨率、FPS、裁剪)。",
+ "tour.src.static": "静态图片 — 使用图片文件测试您的设置。",
+ "tour.src.processed": "处理 — 应用后处理效果,如模糊、亮度或色彩校正。",
+ "tour.src.color_strip": "色带 — 定义屏幕区域如何映射到 LED 段。",
+ "tour.src.audio": "音频 — 分析麦克风或系统音频以实现响应式 LED 效果。",
+ "tour.src.value": "数值 — 用于自动化条件的数字数据源。",
+ "tour.src.sync": "同步时钟 — 在多个源之间同步动画的共享定时器。",
+ "tour.auto.list": "自动化 — 基于时间、音频或数值条件自动激活场景。",
+ "tour.auto.add": "点击 + 创建包含条件和要激活场景的新自动化。",
+ "tour.auto.card": "每张卡片显示自动化状态、条件和快速编辑/切换控制。",
+ "tour.auto.scenes_list": "场景 — 保存的系统状态,自动化可以激活或您可以手动应用。",
+ "tour.auto.scenes_add": "点击 + 将当前系统状态捕获为新的场景预设。",
+ "tour.auto.scenes_card": "每个场景卡片显示目标/设备数量。点击编辑、重新捕获或激活。",
+ "calibration.tutorial.start": "开始教程",
+ "calibration.overlay_toggle": "叠加层",
+ "calibration.start_position": "起始位置:",
+ "calibration.position.bottom_left": "左下",
+ "calibration.position.bottom_right": "右下",
+ "calibration.position.top_left": "左上",
+ "calibration.position.top_right": "右上",
+ "calibration.direction": "方向:",
+ "calibration.direction.clockwise": "顺时针",
+ "calibration.direction.counterclockwise": "逆时针",
+ "calibration.leds.top": "顶部 LED:",
+ "calibration.leds.right": "右侧 LED:",
+ "calibration.leds.bottom": "底部 LED:",
+ "calibration.leds.left": "左侧 LED:",
+ "calibration.offset": "LED 偏移:",
+ "calibration.offset.hint": "从物理 LED 0 到起始角落的距离(沿灯带方向)",
+ "calibration.skip_start": "跳过 LED(起始):",
+ "calibration.skip_start.hint": "灯带起始端关闭的 LED 数量(0 = 无)",
+ "calibration.skip_end": "跳过 LED(末尾):",
+ "calibration.skip_end.hint": "灯带末尾端关闭的 LED 数量(0 = 无)",
+ "calibration.border_width": "边框(像素):",
+ "calibration.border_width.hint": "从屏幕边缘采样多少像素来确定 LED 颜色(1-100)",
+ "calibration.button.cancel": "取消",
+ "calibration.button.save": "保存",
+ "calibration.saved": "校准已保存",
+ "calibration.failed": "保存校准失败",
+ "server.healthy": "服务器在线",
+ "server.offline": "服务器离线",
+ "error.unauthorized": "未授权 - 请先登录",
+ "error.network": "网络错误",
+ "error.unknown": "发生错误",
+ "modal.discard_changes": "有未保存的更改。是否放弃?",
+ "confirm.title": "确认操作",
+ "confirm.yes": "是",
+ "confirm.no": "否",
+ "confirm.stop_all": "停止所有运行中的目标?",
+ "confirm.turn_off_device": "关闭此设备?",
+ "common.loading": "加载中...",
+ "common.delete": "删除",
+ "common.edit": "编辑",
+ "common.clone": "克隆",
+ "common.none": "无",
+ "common.none_no_cspt": "无(无处理模板)",
+ "common.none_no_input": "无(无输入源)",
+ "common.none_own_speed": "无(使用自身速度)",
+ "common.undo": "撤销",
+ "validation.required": "此字段为必填项",
+ "bulk.processing": "处理中…",
+ "api.error.timeout": "请求超时 — 请重试",
+ "api.error.network": "网络错误 — 请检查连接",
+ "palette.search": "搜索…",
+ "section.filter.placeholder": "筛选...",
+ "section.filter.reset": "清除筛选",
+ "tags.label": "标签",
+ "tags.hint": "为卡片分配标签以进行分组和筛选",
+ "tags.placeholder": "添加标签...",
+ "section.expand_all": "全部展开",
+ "section.collapse_all": "全部折叠",
+ "streams.title": "源",
+ "streams.description": "源定义采集管线。原始源使用采集模板从显示器采集。处理源对另一个源应用后处理。将源分配给设备。",
+ "streams.group.raw": "源",
+ "streams.group.raw_templates": "引擎模板",
+ "streams.group.processed": "源",
+ "streams.group.proc_templates": "滤镜模板",
+ "streams.group.css_processing": "处理模板",
+ "streams.group.color_strip": "色带源",
+ "streams.group.audio": "音频",
+ "streams.group.audio_templates": "音频模板",
+ "streams.section.streams": "源",
+ "streams.add": "添加源",
+ "streams.add.raw": "添加屏幕采集",
+ "streams.add.processed": "添加处理源",
+ "streams.edit": "编辑源",
+ "streams.edit.raw": "编辑屏幕采集",
+ "streams.edit.processed": "编辑处理源",
+ "streams.name": "源名称:",
+ "streams.name.placeholder": "我的源",
+ "streams.type": "类型:",
+ "streams.type.raw": "屏幕采集",
+ "streams.type.processed": "已处理",
+ "streams.display": "显示器:",
+ "streams.display.hint": "采集哪个屏幕",
+ "streams.capture_template": "引擎模板:",
+ "streams.capture_template.hint": "定义屏幕采集方式的引擎模板",
+ "streams.target_fps": "目标 FPS:",
+ "streams.target_fps.hint": "采集的目标帧率(1-90)",
+ "streams.source": "源:",
+ "streams.source.hint": "要应用处理滤镜的源",
+ "streams.pp_template": "滤镜模板:",
+ "streams.pp_template.hint": "要应用到源的滤镜模板",
+ "streams.description_label": "描述(可选):",
+ "streams.description_placeholder": "描述此源...",
+ "streams.created": "源创建成功",
+ "streams.updated": "源更新成功",
+ "streams.deleted": "源删除成功",
+ "streams.delete.confirm": "确定要删除此源吗?",
+ "streams.modal.loading": "加载中...",
+ "streams.error.load": "加载源失败",
+ "streams.error.required": "请填写所有必填项",
+ "streams.error.delete": "删除源失败",
+ "streams.test.title": "测试源",
+ "streams.test.run": "运行",
+ "streams.test.running": "正在测试源...",
+ "streams.test.duration": "采集时长(秒):",
+ "streams.test.error.failed": "源测试失败",
+ "postprocessing.title": "滤镜模板",
+ "postprocessing.description": "处理模板定义图像滤镜和色彩校正。将它们分配给处理图片源以实现跨设备的一致后处理。",
+ "postprocessing.add": "添加滤镜模板",
+ "postprocessing.edit": "编辑滤镜模板",
+ "postprocessing.name": "模板名称:",
+ "postprocessing.name.placeholder": "我的滤镜模板",
+ "filters.select_type": "选择滤镜类型...",
+ "filters.add": "添加滤镜",
+ "filters.remove": "移除",
+ "filters.drag_to_reorder": "拖动以重新排序",
+ "filters.empty": "尚未添加滤镜。使用下方选择器添加滤镜。",
+ "filters.brightness": "亮度",
+ "filters.brightness.desc": "调整整体图像亮度",
+ "filters.saturation": "饱和度",
+ "filters.saturation.desc": "增强或降低色彩强度",
+ "filters.gamma": "伽马",
+ "filters.gamma.desc": "非线性亮度曲线校正",
+ "filters.downscaler": "缩小",
+ "filters.downscaler.desc": "降低分辨率以加快处理",
+ "filters.pixelate": "像素化",
+ "filters.pixelate.desc": "马赛克式块平均",
+ "filters.auto_crop": "自动裁剪",
+ "filters.auto_crop.desc": "移除信箱式内容的黑边",
+ "filters.flip": "翻转",
+ "filters.flip.desc": "水平或垂直镜像翻转",
+ "filters.color_correction": "色彩校正",
+ "filters.color_correction.desc": "白平衡和色温调整",
+ "filters.filter_template": "滤镜模板",
+ "filters.filter_template.desc": "嵌入另一个处理模板",
+ "filters.css_filter_template": "色带滤镜模板",
+ "filters.css_filter_template.desc": "嵌入另一个色带处理模板",
+ "filters.frame_interpolation": "帧插值",
+ "filters.frame_interpolation.desc": "帧间混合以获得更平滑的输出",
+ "filters.noise_gate": "噪声门",
+ "filters.noise_gate.desc": "抑制低于阈值的细微色彩变化",
+ "filters.palette_quantization": "调色板量化",
+ "filters.palette_quantization.desc": "将颜色减少到有限调色板",
+ "filters.reverse": "反转",
+ "filters.reverse.desc": "反转色带中的LED顺序",
+ "postprocessing.description_label": "描述(可选):",
+ "postprocessing.description_placeholder": "描述此模板...",
+ "postprocessing.created": "模板创建成功",
+ "postprocessing.updated": "模板更新成功",
+ "postprocessing.deleted": "模板删除成功",
+ "postprocessing.delete.confirm": "确定要删除此滤镜模板吗?",
+ "postprocessing.error.load": "加载处理模板失败",
+ "postprocessing.error.required": "请填写所有必填项",
+ "postprocessing.error.delete": "删除处理模板失败",
+ "postprocessing.config.show": "显示设置",
+ "postprocessing.test.title": "测试滤镜模板",
+ "postprocessing.test.source_stream": "源:",
+ "postprocessing.test.running": "正在测试处理模板...",
+ "postprocessing.test.error.no_stream": "请选择一个源",
+ "postprocessing.test.error.failed": "处理模板测试失败",
+ "css_processing.title": "色带处理模板",
+ "css_processing.add": "添加色带处理模板",
+ "css_processing.edit": "编辑色带处理模板",
+ "css_processing.name": "模板名称:",
+ "css_processing.name_placeholder": "我的色带处理模板",
+ "css_processing.description_label": "描述(可选):",
+ "css_processing.description_placeholder": "描述此模板...",
+ "css_processing.created": "色带处理模板已创建",
+ "css_processing.updated": "色带处理模板已更新",
+ "css_processing.deleted": "色带处理模板已删除",
+ "css_processing.delete.confirm": "确定要删除此色带处理模板吗?",
+ "css_processing.error.required": "请填写所有必填字段",
+ "css_processing.error.load": "加载色带处理模板出错",
+ "css_processing.error.delete": "删除色带处理模板出错",
+ "css_processing.error.clone_failed": "克隆色带处理模板失败",
+ "device.button.stream_selector": "源设置",
+ "device.stream_settings.title": "源设置",
+ "device.stream_selector.label": "源:",
+ "device.stream_selector.hint": "选择一个源来定义此设备采集和处理的内容",
+ "device.stream_selector.none": "-- 未分配源 --",
+ "device.stream_selector.saved": "源设置已更新",
+ "device.stream_settings.border_width": "边框宽度(像素):",
+ "device.stream_settings.border_width_hint": "从屏幕边缘采样多少像素来确定 LED 颜色(1-100)",
+ "device.stream_settings.interpolation": "插值模式:",
+ "device.stream_settings.interpolation.average": "平均",
+ "device.stream_settings.interpolation.median": "中位数",
+ "device.stream_settings.interpolation.dominant": "主色",
+ "device.stream_settings.interpolation_hint": "如何从采样像素计算 LED 颜色",
+ "device.stream_settings.smoothing": "平滑:",
+ "device.stream_settings.smoothing_hint": "帧间时间混合(0=无,1=完全)。减少闪烁。",
+ "device.tip.stream_selector": "为此设备配置图片源和 LED 投影设置",
+ "streams.group.static_image": "静态图片",
+ "streams.add.static_image": "添加静态图片源",
+ "streams.edit.static_image": "编辑静态图片源",
+ "streams.type.static_image": "静态图片",
+ "streams.group.video": "视频",
+ "streams.add.video": "添加视频源",
+ "streams.edit.video": "编辑视频源",
+ "picture_source.type.video": "视频",
+ "picture_source.type.video.desc": "从视频文件、URL或YouTube流式传输帧",
+ "picture_source.video.url": "视频URL:",
+ "picture_source.video.url.hint": "本地文件路径、HTTP URL或YouTube URL",
+ "picture_source.video.url.placeholder": "https://example.com/video.mp4",
+ "picture_source.video.loop": "循环:",
+ "picture_source.video.speed": "播放速度:",
+ "picture_source.video.start_time": "开始时间(秒):",
+ "picture_source.video.end_time": "结束时间(秒):",
+ "picture_source.video.resolution_limit": "最大宽度(像素):",
+ "picture_source.video.resolution_limit.hint": "解码时缩小视频以提高性能",
+ "streams.image_source": "图片源:",
+ "streams.image_source.placeholder": "https://example.com/image.jpg 或 C:\\path\\to\\image.png",
+ "streams.image_source.hint": "输入图片的 URL(http/https)或本地文件路径",
+ "streams.validate_image.validating": "正在验证...",
+ "streams.validate_image.valid": "图片可访问",
+ "streams.validate_image.invalid": "图片不可访问",
+ "targets.title": "目标",
+ "targets.description": "目标将色带源桥接到输出设备。每个目标引用一个设备和一个色带源。",
+ "targets.subtab.wled": "LED",
+ "targets.subtab.led": "LED",
+ "targets.section.devices": "设备",
+ "targets.section.color_strips": "色带源",
+ "targets.section.targets": "目标",
+ "targets.section.specific_settings": "特定设置",
+ "targets.section.advanced": "高级",
+ "targets.add": "添加目标",
+ "targets.edit": "编辑目标",
+ "targets.loading": "正在加载目标...",
+ "targets.none": "尚未配置目标",
+ "targets.failed": "加载目标失败",
+ "targets.name": "目标名称:",
+ "targets.name.placeholder": "我的目标",
+ "targets.device": "设备:",
+ "targets.device.hint": "选择要发送数据的 LED 设备",
+ "targets.device.none": "-- 选择设备 --",
+ "targets.color_strip_source": "色带源:",
+ "targets.color_strip_source.hint": "选择为此目标提供 LED 颜色的色带源",
+ "targets.no_css": "无源",
+ "targets.source": "源:",
+ "targets.source.hint": "要采集和处理的图片源",
+ "targets.source.none": "-- 未分配源 --",
+ "targets.metrics.pipeline": "管线详情",
+ "targets.fps": "目标 FPS:",
+ "targets.fps.hint": "采集和 LED 更新的目标帧率(1-90)",
+ "targets.fps.rec": "硬件最大 ≈ {fps} fps({leds} 个 LED)",
+ "targets.border_width": "边框宽度(像素):",
+ "targets.border_width.hint": "从屏幕边缘采样多少像素来确定 LED 颜色(1-100)",
+ "targets.interpolation": "插值模式:",
+ "targets.interpolation.hint": "如何从采样像素计算 LED 颜色",
+ "targets.interpolation.average": "平均",
+ "targets.interpolation.median": "中位数",
+ "targets.interpolation.dominant": "主色",
+ "targets.smoothing": "平滑:",
+ "targets.smoothing.hint": "帧间时间混合(0=无,1=完全)。减少闪烁。",
+ "targets.keepalive_interval": "心跳间隔:",
+ "targets.keepalive_interval.hint": "源静态时重新发送最后一帧的频率,保持设备在活动模式(0.5-5.0秒)",
+ "targets.created": "目标创建成功",
+ "targets.updated": "目标更新成功",
+ "targets.deleted": "目标删除成功",
+ "targets.delete.confirm": "确定要删除此目标吗?",
+ "targets.error.load": "加载目标失败",
+ "targets.error.required": "请填写所有必填项",
+ "targets.error.name_required": "请输入目标名称",
+ "targets.error.delete": "删除目标失败",
+ "targets.button.start": "启动",
+ "targets.button.stop": "停止",
+ "targets.status.processing": "处理中",
+ "targets.status.idle": "空闲",
+ "targets.status.error": "错误",
+ "targets.metrics.actual_fps": "实际 FPS",
+ "targets.metrics.target_fps": "目标 FPS",
+ "targets.metrics.frames": "帧数",
+ "targets.metrics.errors": "错误",
+ "targets.subtab.key_colors": "关键颜色",
+ "targets.section.key_colors": "关键颜色目标",
+ "kc.add": "添加关键颜色目标",
+ "kc.edit": "编辑关键颜色目标",
+ "kc.name": "目标名称:",
+ "kc.name.placeholder": "我的关键颜色目标",
+ "kc.source": "图片源:",
+ "kc.source.hint": "从哪个图片源提取颜色",
+ "kc.source.none": "-- 未分配源 --",
+ "kc.fps": "提取 FPS:",
+ "kc.fps.hint": "每秒提取颜色的次数(1-60)",
+ "kc.interpolation": "颜色模式:",
+ "kc.interpolation.hint": "如何从每个矩形中的像素计算关键颜色",
+ "kc.interpolation.average": "平均",
+ "kc.interpolation.median": "中位数",
+ "kc.interpolation.dominant": "主色",
+ "kc.interpolation.average.desc": "所有像素颜色的平均值",
+ "kc.interpolation.median.desc": "每通道中间颜色值",
+ "kc.interpolation.dominant.desc": "出现最频繁的颜色",
+ "kc.smoothing": "平滑:",
+ "kc.smoothing.hint": "提取间的时间混合(0=无,1=完全)",
+ "kc.pattern_template": "图案模板:",
+ "kc.pattern_template.hint": "选择用于颜色提取的矩形图案",
+ "kc.pattern_template.none": "-- 选择图案模板 --",
+ "kc.brightness_vs": "亮度源:",
+ "kc.brightness_vs.hint": "可选的值源,每帧动态控制亮度(与手动亮度滑块相乘)",
+ "kc.brightness_vs.none": "无(仅手动亮度)",
+ "kc.created": "关键颜色目标创建成功",
+ "kc.updated": "关键颜色目标更新成功",
+ "kc.deleted": "关键颜色目标删除成功",
+ "kc.delete.confirm": "确定要删除此关键颜色目标吗?",
+ "kc.error.no_pattern": "请选择图案模板",
+ "kc.error.required": "请填写所有必填项",
+ "kc.colors.none": "尚未提取颜色",
+ "kc.test": "测试",
+ "kc.test.error": "测试失败",
+ "targets.section.pattern_templates": "图案模板",
+ "pattern.add": "添加图案模板",
+ "pattern.edit": "编辑图案模板",
+ "pattern.name": "模板名称:",
+ "pattern.name.placeholder": "我的图案模板",
+ "pattern.description_label": "描述(可选):",
+ "pattern.description_placeholder": "描述此图案...",
+ "pattern.rectangles": "矩形",
+ "pattern.rect.name": "名称",
+ "pattern.rect.x": "X",
+ "pattern.rect.y": "Y",
+ "pattern.rect.width": "宽",
+ "pattern.rect.height": "高",
+ "pattern.rect.add": "添加矩形",
+ "pattern.rect.remove": "移除",
+ "pattern.rect.empty": "尚未定义矩形。请至少添加一个矩形。",
+ "pattern.created": "图案模板创建成功",
+ "pattern.updated": "图案模板更新成功",
+ "pattern.deleted": "图案模板删除成功",
+ "pattern.delete.confirm": "确定要删除此图案模板吗?",
+ "pattern.delete.referenced": "无法删除:此模板正被目标引用",
+ "pattern.error.required": "请填写所有必填项",
+ "pattern.visual_editor": "可视编辑器",
+ "pattern.capture_bg": "采集背景",
+ "pattern.source_for_bg": "背景源:",
+ "pattern.source_for_bg.none": "-- 选择源 --",
+ "pattern.delete_selected": "删除选中",
+ "pattern.name.hint": "此矩形布局的描述性名称",
+ "pattern.description.hint": "关于此图案使用位置或方式的可选说明",
+ "pattern.visual_editor.hint": "点击 + 按钮添加矩形。拖动边缘调整大小,拖动内部移动位置。",
+ "pattern.rectangles.hint": "用精确坐标(0.0 到 1.0)微调矩形位置和大小",
+ "overlay.toggle": "切换屏幕叠加层",
+ "overlay.button.show": "显示叠加层可视化",
+ "overlay.button.hide": "隐藏叠加层可视化",
+ "overlay.started": "叠加层可视化已启动",
+ "overlay.stopped": "叠加层可视化已停止",
+ "overlay.error.start": "启动叠加层失败",
+ "overlay.error.stop": "停止叠加层失败",
+ "dashboard.title": "仪表盘",
+ "dashboard.section.targets": "目标",
+ "dashboard.section.running": "运行中",
+ "dashboard.section.stopped": "已停止",
+ "dashboard.no_targets": "尚未配置目标",
+ "dashboard.uptime": "运行时长",
+ "dashboard.fps": "FPS",
+ "dashboard.errors": "错误",
+ "dashboard.device": "设备",
+ "dashboard.stop_all": "全部停止",
+ "dashboard.failed": "加载仪表盘失败",
+ "dashboard.section.automations": "自动化",
+ "dashboard.section.scenes": "场景预设",
+ "dashboard.section.sync_clocks": "同步时钟",
+ "dashboard.targets": "目标",
+ "dashboard.section.performance": "系统性能",
+ "dashboard.perf.cpu": "CPU",
+ "dashboard.perf.ram": "内存",
+ "dashboard.perf.gpu": "GPU",
+ "dashboard.perf.unavailable": "不可用",
+ "dashboard.perf.color": "图表颜色",
+ "dashboard.poll_interval": "刷新间隔",
+ "automations.title": "自动化",
+ "automations.empty": "尚未配置自动化。创建一个以自动激活场景。",
+ "automations.add": "添加自动化",
+ "automations.edit": "编辑自动化",
+ "automations.delete.confirm": "删除自动化 \"{name}\"?",
+ "automations.name": "名称:",
+ "automations.name.hint": "此自动化的描述性名称",
+ "automations.name.placeholder": "我的自动化",
+ "automations.enabled": "启用:",
+ "automations.enabled.hint": "禁用的自动化即使满足条件也不会激活",
+ "automations.condition_logic": "条件逻辑:",
+ "automations.condition_logic.hint": "多个条件的组合方式:任一(或)或 全部(与)",
+ "automations.condition_logic.or": "任一条件(或)",
+ "automations.condition_logic.and": "全部条件(与)",
+ "automations.condition_logic.or.desc": "任一条件匹配时触发",
+ "automations.condition_logic.and.desc": "全部匹配时才触发",
+ "automations.conditions": "条件:",
+ "automations.conditions.hint": "决定此自动化何时激活的规则",
+ "automations.conditions.add": "添加条件",
+ "automations.conditions.empty": "无条件 — 启用后自动化始终处于活动状态",
+ "automations.condition.always": "始终",
+ "automations.condition.always.desc": "始终活跃",
+ "automations.condition.always.hint": "自动化启用后立即激活并保持活动。",
+ "automations.condition.startup": "启动",
+ "automations.condition.startup.desc": "服务器启动时",
+ "automations.condition.startup.hint": "服务器启动时激活,启用期间保持活动。",
+ "automations.condition.application": "应用程序",
+ "automations.condition.application.desc": "应用运行/聚焦",
+ "automations.condition.application.apps": "应用程序:",
+ "automations.condition.application.apps.hint": "进程名,每行一个(例如 firefox.exe)",
+ "automations.condition.application.browse": "浏览",
+ "automations.condition.application.search": "筛选进程...",
+ "automations.condition.application.no_processes": "未找到进程",
+ "automations.condition.application.match_type": "匹配类型:",
+ "automations.condition.application.match_type.hint": "如何检测应用程序",
+ "automations.condition.application.match_type.running": "运行中",
+ "automations.condition.application.match_type.running.desc": "进程活跃",
+ "automations.condition.application.match_type.topmost": "最前",
+ "automations.condition.application.match_type.topmost.desc": "前台窗口",
+ "automations.condition.application.match_type.topmost_fullscreen": "最前 + 全屏",
+ "automations.condition.application.match_type.topmost_fullscreen.desc": "前台 + 全屏",
+ "automations.condition.application.match_type.fullscreen": "全屏",
+ "automations.condition.application.match_type.fullscreen.desc": "任意全屏应用",
+ "automations.condition.time_of_day": "时段",
+ "automations.condition.time_of_day.desc": "时间范围",
+ "automations.condition.time_of_day.start_time": "开始时间:",
+ "automations.condition.time_of_day.end_time": "结束时间:",
+ "automations.condition.time_of_day.overnight_hint": "跨夜时段(如 22:00–06:00),请将开始时间设为晚于结束时间。",
+ "automations.condition.system_idle": "系统空闲",
+ "automations.condition.system_idle.desc": "空闲/活跃",
+ "automations.condition.system_idle.idle_minutes": "空闲超时(分钟):",
+ "automations.condition.system_idle.mode": "触发模式:",
+ "automations.condition.system_idle.when_idle": "空闲时",
+ "automations.condition.system_idle.when_active": "活跃时",
+ "automations.condition.display_state": "显示器状态",
+ "automations.condition.display_state.desc": "显示器开/关",
+ "automations.condition.display_state.state": "显示器状态:",
+ "automations.condition.display_state.on": "开启",
+ "automations.condition.display_state.off": "关闭(休眠)",
+ "automations.condition.mqtt": "MQTT",
+ "automations.condition.mqtt.desc": "MQTT 消息",
+ "automations.condition.mqtt.topic": "主题:",
+ "automations.condition.mqtt.payload": "消息内容:",
+ "automations.condition.mqtt.match_mode": "匹配模式:",
+ "automations.condition.mqtt.match_mode.exact": "精确匹配",
+ "automations.condition.mqtt.match_mode.contains": "包含",
+ "automations.condition.mqtt.match_mode.regex": "正则表达式",
+ "automations.condition.mqtt.hint": "当 MQTT 主题收到匹配的消息时激活",
+ "automations.condition.webhook": "Webhook",
+ "automations.condition.webhook.desc": "HTTP 回调",
+ "automations.condition.webhook.hint": "通过外部服务的 HTTP 请求激活(Home Assistant、IFTTT、curl 等)",
+ "automations.condition.webhook.url": "Webhook URL:",
+ "automations.condition.webhook.copy": "复制",
+ "automations.condition.webhook.copied": "已复制!",
+ "automations.condition.webhook.save_first": "请先保存自动化以生成 Webhook URL",
+ "automations.scene": "场景:",
+ "automations.scene.hint": "条件满足时激活的场景预设",
+ "automations.scene.search_placeholder": "搜索场景...",
+ "automations.scene.none_selected": "无(无场景)",
+ "automations.scene.none_available": "没有可用的场景",
+ "automations.deactivation_mode": "停用方式:",
+ "automations.deactivation_mode.hint": "条件不再满足时的行为",
+ "automations.deactivation_mode.none": "无",
+ "automations.deactivation_mode.none.desc": "保持当前状态",
+ "automations.deactivation_mode.revert": "恢复",
+ "automations.deactivation_mode.revert.desc": "恢复到之前的状态",
+ "automations.deactivation_mode.fallback_scene": "备用",
+ "automations.deactivation_mode.fallback_scene.desc": "激活备用场景",
+ "automations.deactivation_scene": "备用场景:",
+ "automations.deactivation_scene.hint": "自动化停用时激活的场景",
+ "automations.status.active": "活动",
+ "automations.status.inactive": "非活动",
+ "automations.status.disabled": "已禁用",
+ "automations.action.disable": "禁用",
+ "automations.last_activated": "上次激活",
+ "automations.logic.and": " 与 ",
+ "automations.logic.or": " 或 ",
+ "automations.logic.all": "全部",
+ "automations.logic.any": "任一",
+ "automations.updated": "自动化已更新",
+ "automations.created": "自动化已创建",
+ "automations.deleted": "自动化已删除",
+ "automations.error.name_required": "名称为必填项",
+ "automations.error.clone_failed": "克隆自动化失败",
+ "scenes.title": "场景",
+ "scenes.add": "捕获场景",
+ "scenes.edit": "编辑场景",
+ "scenes.name": "名称:",
+ "scenes.name.hint": "此场景预设的描述性名称",
+ "scenes.name.placeholder": "我的场景",
+ "scenes.description": "描述:",
+ "scenes.description.hint": "此场景功能的可选描述",
+ "scenes.targets": "目标:",
+ "scenes.targets.hint": "选择要包含在此场景快照中的目标",
+ "scenes.targets.add": "添加目标",
+ "scenes.targets.search_placeholder": "搜索目标...",
+ "scenes.capture": "捕获",
+ "scenes.activate": "激活场景",
+ "scenes.recapture": "重新捕获当前状态",
+ "scenes.delete": "删除场景",
+ "scenes.targets_count": "目标",
+ "scenes.captured": "场景已捕获",
+ "scenes.updated": "场景已更新",
+ "scenes.activated": "场景已激活",
+ "scenes.activated_partial": "场景部分激活",
+ "scenes.errors": "错误",
+ "scenes.recaptured": "场景已重新捕获",
+ "scenes.deleted": "场景已删除",
+ "scenes.recapture_confirm": "将当前状态重新捕获到\"{name}\"中?",
+ "scenes.delete_confirm": "删除场景\"{name}\"?",
+ "scenes.error.name_required": "名称为必填项",
+ "scenes.error.save_failed": "保存场景失败",
+ "scenes.error.activate_failed": "激活场景失败",
+ "scenes.error.recapture_failed": "重新捕获场景失败",
+ "scenes.error.delete_failed": "删除场景失败",
+ "scenes.cloned": "场景已克隆",
+ "scenes.error.clone_failed": "克隆场景失败",
+ "time.hours_minutes": "{h}时 {m}分",
+ "time.minutes_seconds": "{m}分 {s}秒",
+ "time.seconds": "{s}秒",
+ "dashboard.type.led": "LED",
+ "dashboard.type.kc": "关键颜色",
+ "aria.close": "关闭",
+ "aria.save": "保存",
+ "aria.cancel": "取消",
+ "aria.previous": "上一个",
+ "aria.next": "下一个",
+ "aria.hint": "显示提示",
+ "color_strip.select_type": "选择色带类型",
+ "color_strip.add": "添加色带源",
+ "color_strip.edit": "编辑色带源",
+ "color_strip.name": "名称:",
+ "color_strip.name.placeholder": "墙壁灯带",
+ "color_strip.picture_source": "图片源:",
+ "color_strip.picture_source.hint": "用作 LED 颜色计算输入的屏幕采集源",
+ "color_strip.fps": "目标 FPS:",
+ "color_strip.fps.hint": "LED 颜色更新的目标帧率(10-90)",
+ "color_strip.interpolation": "颜色模式:",
+ "color_strip.interpolation.hint": "如何从采样的边框像素计算 LED 颜色",
+ "color_strip.interpolation.average": "平均",
+ "color_strip.interpolation.median": "中位数",
+ "color_strip.interpolation.dominant": "主色",
+ "color_strip.interpolation.average.desc": "将所有采样像素混合为平滑颜色",
+ "color_strip.interpolation.median.desc": "取中间颜色值,减少异常值",
+ "color_strip.interpolation.dominant.desc": "使用样本中出现最频繁的颜色",
+ "color_strip.smoothing": "平滑:",
+ "color_strip.smoothing.hint": "帧间时间混合(0=无,1=完全)。减少闪烁。",
+ "color_strip.frame_interpolation": "帧插值:",
+ "color_strip.frame_interpolation.hint": "在连续采集帧之间混合,以在采集速率较低时仍以完整目标 FPS 输出。减少慢速环境过渡时的可见阶梯效应。",
+ "color_strip.color_corrections": "色彩校正",
+ "color_strip.brightness": "亮度:",
+ "color_strip.brightness.hint": "输出亮度倍数(0=关闭,1=不变,2=加倍)。在颜色提取后应用。",
+ "color_strip.saturation": "饱和度:",
+ "color_strip.saturation.hint": "颜色饱和度(0=灰度,1=不变,2=双倍饱和度)",
+ "color_strip.gamma": "伽马:",
+ "color_strip.gamma.hint": "伽马校正(1=无,<1=更亮的中间调,>1=更暗的中间调)",
+ "color_strip.test_device": "测试设备:",
+ "color_strip.test_device.hint": "选择一个设备,在点击边缘切换时发送测试像素",
+ "color_strip.leds": "LED 数量",
+ "color_strip.led_count": "LED 数量:",
+ "color_strip.led_count.hint": "物理灯带上的 LED 总数。屏幕源:0 = 从校准自动获取(未映射到边缘的额外 LED 将为黑色)。静态颜色:设置为与设备 LED 数量匹配。",
+ "color_strip.created": "色带源已创建",
+ "color_strip.updated": "色带源已更新",
+ "color_strip.deleted": "色带源已删除",
+ "color_strip.delete.confirm": "确定要删除此色带源吗?",
+ "color_strip.delete.referenced": "无法删除:此源正在被目标使用",
+ "color_strip.error.name_required": "请输入名称",
+ "color_strip.type": "类型:",
+ "color_strip.type.hint": "图片源从屏幕采集推导 LED 颜色。静态颜色用单一颜色填充所有 LED。渐变在所有 LED 上分布颜色渐变。颜色循环平滑循环用户定义的颜色列表。组合将多个源作为混合图层叠加。音频响应从实时音频输入驱动 LED。API 输入通过 REST 或 WebSocket 从外部客户端接收原始 LED 颜色。",
+ "color_strip.type.picture": "图片源",
+ "color_strip.type.picture.desc": "从屏幕捕获获取颜色",
+ "color_strip.type.picture_advanced": "多显示器",
+ "color_strip.type.picture_advanced.desc": "跨显示器的线条校准",
+ "color_strip.type.static": "静态颜色",
+ "color_strip.type.static.desc": "单色填充",
+ "color_strip.type.gradient": "渐变",
+ "color_strip.type.gradient.desc": "LED上的平滑颜色过渡",
+ "color_strip.type.color_cycle": "颜色循环",
+ "color_strip.type.color_cycle.desc": "循环切换颜色列表",
+ "color_strip.static_color": "颜色:",
+ "color_strip.static_color.hint": "将发送到灯带上所有 LED 的纯色。",
+ "color_strip.gradient.preview": "渐变:",
+ "color_strip.gradient.preview.hint": "可视预览。点击下方标记轨道添加色标。拖动标记重新定位。",
+ "color_strip.gradient.stops": "色标:",
+ "color_strip.gradient.stops.hint": "每个色标在相对位置定义一种颜色(0.0 = 起始,1.0 = 结束)。↔ 按钮添加右侧颜色以在该色标处创建硬边。",
+ "color_strip.gradient.stops_count": "个色标",
+ "color_strip.gradient.add_stop": "+ 添加色标",
+ "color_strip.gradient.position": "位置(0.0-1.0)",
+ "color_strip.gradient.bidir.hint": "在此色标右侧添加第二种颜色以在渐变中创建硬边。",
+ "color_strip.gradient.min_stops": "渐变至少需要 2 个色标",
+ "color_strip.gradient.preset": "预设:",
+ "color_strip.gradient.preset.hint": "加载预定义的渐变调色板。选择预设将替换当前色标。",
+ "color_strip.gradient.preset.custom": "— 自定义 —",
+ "color_strip.gradient.preset.rainbow": "彩虹",
+ "color_strip.gradient.preset.sunset": "日落",
+ "color_strip.gradient.preset.ocean": "海洋",
+ "color_strip.gradient.preset.forest": "森林",
+ "color_strip.gradient.preset.fire": "火焰",
+ "color_strip.gradient.preset.lava": "熔岩",
+ "color_strip.gradient.preset.aurora": "极光",
+ "color_strip.gradient.preset.ice": "冰",
+ "color_strip.gradient.preset.warm": "暖色",
+ "color_strip.gradient.preset.cool": "冷色",
+ "color_strip.gradient.preset.neon": "霓虹",
+ "color_strip.gradient.preset.pastel": "柔和",
+ "color_strip.gradient.preset.save_button": "保存为预设…",
+ "color_strip.gradient.preset.save_prompt": "输入预设名称:",
+ "color_strip.gradient.preset.saved": "预设已保存",
+ "color_strip.gradient.preset.deleted": "预设已删除",
+ "color_strip.gradient.preset.apply": "应用",
+ "color_strip.animation": "动画",
+ "color_strip.animation.type": "效果:",
+ "color_strip.animation.type.hint": "要应用的动画效果。",
+ "color_strip.animation.type.none": "无(无动画效果)",
+ "color_strip.animation.type.none.desc": "静态颜色,无动画",
+ "color_strip.animation.type.breathing": "呼吸",
+ "color_strip.animation.type.breathing.desc": "平滑的亮度渐入渐出",
+ "color_strip.animation.type.color_cycle": "颜色循环",
+ "color_strip.animation.type.gradient_shift": "渐变移动",
+ "color_strip.animation.type.gradient_shift.desc": "渐变沿灯带滑动",
+ "color_strip.animation.type.wave": "波浪",
+ "color_strip.animation.type.wave.desc": "沿灯带移动的正弦亮度波",
+ "color_strip.animation.type.strobe": "频闪",
+ "color_strip.animation.type.strobe.desc": "快速开/关闪烁",
+ "color_strip.animation.type.sparkle": "闪烁",
+ "color_strip.animation.type.sparkle.desc": "随机 LED 短暂闪亮",
+ "color_strip.animation.type.pulse": "脉冲",
+ "color_strip.animation.type.pulse.desc": "快速衰减的尖锐亮度脉冲",
+ "color_strip.animation.type.candle": "烛光",
+ "color_strip.animation.type.candle.desc": "温暖的类似蜡烛的闪烁光芒",
+ "color_strip.animation.type.rainbow_fade": "彩虹渐变",
+ "color_strip.animation.type.rainbow_fade.desc": "循环整个色相光谱",
+ "color_strip.animation.speed": "速度:",
+ "color_strip.animation.speed.hint": "动画速度倍数。1.0 ≈ 呼吸效果每秒一个循环;更高值循环更快。",
+ "color_strip.color_cycle.colors": "颜色:",
+ "color_strip.color_cycle.colors.hint": "平滑循环的颜色列表。至少需要 2 种。默认为全彩虹光谱。",
+ "color_strip.color_cycle.add_color": "+ 添加颜色",
+ "color_strip.color_cycle.speed": "速度:",
+ "color_strip.color_cycle.speed.hint": "循环速度倍数。1.0 ≈ 每 20 秒一个完整循环;更高值循环更快。",
+ "color_strip.color_cycle.min_colors": "颜色循环至少需要 2 种颜色",
+ "color_strip.type.effect": "效果",
+ "color_strip.type.effect.desc": "程序化效果:火焰、等离子、极光",
+ "color_strip.type.effect.hint": "实时生成的程序化 LED 效果(火焰、流星、等离子、噪声、极光)。",
+ "color_strip.type.composite": "组合",
+ "color_strip.type.composite.desc": "叠加和混合多个源",
+ "color_strip.type.composite.hint": "将多个色带源作为图层叠加,支持混合模式和不透明度。",
+ "color_strip.type.mapped": "映射",
+ "color_strip.type.mapped.desc": "为LED区域分配源",
+ "color_strip.type.mapped.hint": "将不同色带源分配到不同 LED 范围(区域)。与组合的图层混合不同,映射将源并排放置。",
+ "color_strip.type.audio": "音频响应",
+ "color_strip.type.audio.desc": "由音频输入驱动LED",
+ "color_strip.type.audio.hint": "LED 颜色由实时音频输入驱动 — 系统音频或麦克风。",
+ "color_strip.type.api_input": "API 输入",
+ "color_strip.type.api_input.desc": "从外部应用接收颜色",
+ "color_strip.type.api_input.hint": "通过 REST POST 或 WebSocket 从外部客户端接收原始 LED 颜色数组。用于与自定义软件、家庭自动化或任何能发送 HTTP 请求的系统集成。",
+ "color_strip.api_input.fallback_color": "备用颜色:",
+ "color_strip.api_input.fallback_color.hint": "超时未收到数据时显示的颜色。启动时和连接丢失后 LED 将显示此颜色。",
+ "color_strip.api_input.timeout": "超时(秒):",
+ "color_strip.api_input.timeout.hint": "等待新颜色数据多长时间后恢复为备用颜色。设为 0 表示永不超时。",
+ "color_strip.api_input.endpoints": "推送端点:",
+ "color_strip.api_input.endpoints.hint": "使用这些 URL 从外部应用程序推送 LED 颜色数据。REST 接受 JSON,WebSocket 接受 JSON 和原始二进制帧。",
+ "color_strip.api_input.save_first": "请先保存源以查看推送端点 URL。",
+ "color_strip.type.notification": "通知",
+ "color_strip.type.notification.desc": "通过Webhook触发的一次性效果",
+ "color_strip.type.notification.hint": "通过 Webhook 触发时显示一次性视觉效果(闪烁、脉冲、扫描)。设计为组合源中的叠加层。",
+ "color_strip.notification.effect": "效果:",
+ "color_strip.notification.effect.hint": "通知触发时的视觉效果。闪烁线性衰减,脉冲平滑钟形曲线,扫描从左到右填充后衰减。",
+ "color_strip.notification.effect.flash": "闪烁",
+ "color_strip.notification.effect.flash.desc": "瞬时点亮,线性衰减",
+ "color_strip.notification.effect.pulse": "脉冲",
+ "color_strip.notification.effect.pulse.desc": "平滑钟形发光",
+ "color_strip.notification.effect.sweep": "扫描",
+ "color_strip.notification.effect.sweep.desc": "从左到右填充然后消失",
+ "color_strip.notification.duration": "持续时间(毫秒):",
+ "color_strip.notification.duration.hint": "通知效果播放的时长(毫秒)。",
+ "color_strip.notification.default_color": "默认颜色:",
+ "color_strip.notification.default_color.hint": "当通知没有应用特定颜色映射时使用的颜色。",
+ "color_strip.notification.filter_mode": "应用过滤:",
+ "color_strip.notification.filter_mode.hint": "按应用名称过滤通知。关闭=接受全部,白名单=仅列出的应用,黑名单=排除列出的应用。",
+ "color_strip.notification.filter_mode.off": "关闭",
+ "color_strip.notification.filter_mode.whitelist": "白名单",
+ "color_strip.notification.filter_mode.blacklist": "黑名单",
+ "color_strip.notification.filter_mode.off.desc": "接受所有通知",
+ "color_strip.notification.filter_mode.whitelist.desc": "仅列出的应用",
+ "color_strip.notification.filter_mode.blacklist.desc": "排除列出的应用",
+ "color_strip.notification.filter_list": "应用列表:",
+ "color_strip.notification.filter_list.hint": "每行一个应用名称。使用「浏览」从运行中的进程中选择。",
+ "color_strip.notification.filter_list.placeholder": "Discord\nSlack\nTelegram",
+ "color_strip.notification.app_colors": "应用颜色",
+ "color_strip.notification.app_colors.label": "颜色映射:",
+ "color_strip.notification.app_colors.hint": "每个应用的自定义通知颜色。每行将一个应用名称映射到特定颜色。",
+ "color_strip.notification.app_colors.add": "+ 添加映射",
+ "color_strip.notification.endpoint": "Webhook 端点:",
+ "color_strip.notification.endpoint.hint": "使用此 URL 从外部系统触发通知。POST 请求可选 JSON:{\"app\": \"AppName\", \"color\": \"#FF0000\"}。",
+ "color_strip.notification.save_first": "请先保存源以查看 Webhook 端点 URL。",
+ "color_strip.notification.app_count": "个应用",
+ "color_strip.notification.test": "测试通知",
+ "color_strip.notification.test.ok": "通知已发送",
+ "color_strip.notification.test.no_streams": "此源没有运行中的流",
+ "color_strip.notification.test.error": "发送通知失败",
+ "color_strip.notification.history.title": "通知历史",
+ "color_strip.notification.history.hint": "监听器捕获的最近OS通知(最新在前),最多50条。",
+ "color_strip.notification.history.empty": "尚未捕获任何通知",
+ "color_strip.notification.history.unavailable": "此平台不支持OS通知监听器",
+ "color_strip.notification.history.error": "加载通知历史失败",
+ "color_strip.notification.history.refresh": "刷新",
+ "color_strip.notification.history.unknown_app": "未知应用",
+ "color_strip.notification.history.fired": "触发的流数量",
+ "color_strip.notification.history.filtered": "过滤的流数量",
+ "color_strip.test.title": "预览测试",
+ "color_strip.test.connecting": "连接中...",
+ "color_strip.test.error": "无法连接到预览流",
+ "color_strip.test.led_count": "LED数量:",
+ "color_strip.test.fps": "FPS:",
+ "color_strip.test.receive_fps": "接收帧率",
+ "color_strip.test.apply": "应用",
+ "color_strip.test.composite": "合成",
+ "color_strip.preview.title": "实时预览",
+ "color_strip.preview.not_connected": "未连接",
+ "color_strip.preview.connecting": "连接中...",
+ "color_strip.preview.connected": "已连接",
+ "color_strip.preview.unsupported": "此源类型不支持预览",
+ "color_strip.type.daylight": "日光循环",
+ "color_strip.type.daylight.desc": "模拟24小时自然日光变化",
+ "color_strip.type.daylight.hint": "模拟太阳在24小时内的色温变化——从温暖的日出到冷白的日光,再到温暖的日落和昏暗的夜晚。",
+ "color_strip.daylight.speed": "速度:",
+ "color_strip.daylight.speed.hint": "循环速度倍数。1.0 = 约4分钟完成一个完整的昼夜循环。",
+ "color_strip.daylight.use_real_time": "使用实时时间:",
+ "color_strip.daylight.use_real_time.hint": "启用后,LED颜色匹配计算机的实际时间。速度设置将被忽略。",
+ "color_strip.daylight.real_time": "实时",
+ "color_strip.daylight.latitude": "纬度:",
+ "color_strip.daylight.latitude.hint": "地理纬度(-90到90)。影响实时模式下的日出/日落时间。",
+ "color_strip.type.candlelight": "烛光",
+ "color_strip.type.candlelight.desc": "逼真的烛光闪烁模拟",
+ "color_strip.type.candlelight.hint": "在所有LED上模拟逼真的蜡烛闪烁,具有温暖色调和有机闪烁模式。",
+ "color_strip.candlelight.color": "基础颜色:",
+ "color_strip.candlelight.color.hint": "蜡烛火焰的温暖基础颜色。默认为自然温暖的琥珀色。",
+ "color_strip.candlelight.intensity": "闪烁强度:",
+ "color_strip.candlelight.intensity.hint": "蜡烛闪烁程度。低值产生柔和光芒,高值模拟风中的蜡烛。",
+ "color_strip.candlelight.num_candles_label": "蜡烛数量:",
+ "color_strip.candlelight.num_candles": "支蜡烛",
+ "color_strip.candlelight.num_candles.hint": "灯带上独立蜡烛光源的数量。每支蜡烛有自己的闪烁模式。",
+ "color_strip.candlelight.speed": "闪烁速度:",
+ "color_strip.candlelight.speed.hint": "闪烁动画的速度。较高的值产生更快、更不安定的火焰。",
+ "color_strip.type.processed": "已处理",
+ "color_strip.type.processed.desc": "将处理模板应用于另一个源",
+ "color_strip.type.processed.hint": "包装现有色带源并通过滤镜链处理其输出。",
+ "color_strip.processed.input": "源:",
+ "color_strip.processed.input.hint": "将被处理的色带源",
+ "color_strip.processed.template": "处理模板:",
+ "color_strip.processed.template.hint": "应用于输入源输出的滤镜链",
+ "color_strip.processed.error.no_input": "请选择输入源",
+ "color_strip.composite.layers": "图层:",
+ "color_strip.composite.layers.hint": "叠加多个色带源。第一个图层在底部,最后一个在顶部。每个图层可以有自己的混合模式和不透明度。",
+ "color_strip.composite.add_layer": "+ 添加图层",
+ "color_strip.composite.source": "源",
+ "color_strip.composite.blend_mode": "混合",
+ "color_strip.composite.blend_mode.normal": "正常",
+ "color_strip.composite.blend_mode.normal.desc": "标准 Alpha 混合",
+ "color_strip.composite.blend_mode.add": "叠加",
+ "color_strip.composite.blend_mode.add.desc": "通过叠加颜色提亮",
+ "color_strip.composite.blend_mode.multiply": "正片叠底",
+ "color_strip.composite.blend_mode.multiply.desc": "通过相乘颜色变暗",
+ "color_strip.composite.blend_mode.screen": "滤色",
+ "color_strip.composite.blend_mode.screen.desc": "提亮,正片叠底的反转",
+ "color_strip.composite.blend_mode.override": "覆盖",
+ "color_strip.composite.blend_mode.override.desc": "黑色=透明,亮色=不透明",
+ "color_strip.composite.opacity": "不透明度",
+ "color_strip.composite.brightness": "亮度",
+ "color_strip.composite.brightness.none": "无(全亮度)",
+ "color_strip.composite.processing": "处理",
+ "color_strip.composite.enabled": "启用",
+ "color_strip.composite.error.min_layers": "至少需要 1 个图层",
+ "color_strip.composite.error.no_source": "每个图层必须选择一个源",
+ "color_strip.composite.layers_count": "个图层",
+ "color_strip.mapped.zones": "区域:",
+ "color_strip.mapped.zones.hint": "每个区域将色带源映射到特定 LED 范围。区域并排放置 — 区域之间的间隙保持黑色。",
+ "color_strip.mapped.add_zone": "+ 添加区域",
+ "color_strip.mapped.zone_source": "源",
+ "color_strip.mapped.zone_start": "起始 LED",
+ "color_strip.mapped.zone_end": "结束 LED",
+ "color_strip.mapped.zone_reverse": "反转",
+ "color_strip.mapped.zones_count": "个区域",
+ "color_strip.mapped.select_source": "搜索源...",
+ "color_strip.mapped.error.no_source": "每个区域必须选择一个源",
+ "color_strip.audio.visualization": "可视化:",
+ "color_strip.audio.visualization.hint": "音频数据如何渲染到 LED。",
+ "color_strip.audio.viz.spectrum": "频谱分析",
+ "color_strip.audio.viz.spectrum.desc": "频率条分布在灯带上",
+ "color_strip.audio.viz.beat_pulse": "节拍脉冲",
+ "color_strip.audio.viz.beat_pulse.desc": "所有LED随节拍脉动",
+ "color_strip.audio.viz.vu_meter": "VU 表",
+ "color_strip.audio.viz.vu_meter.desc": "音量填充灯带",
+ "color_strip.audio.source": "音频源:",
+ "color_strip.audio.source.hint": "此可视化的音频源。可以是多声道(设备)或单声道(单通道)源。在源标签页中创建和管理音频源。",
+ "color_strip.audio.sensitivity": "灵敏度:",
+ "color_strip.audio.sensitivity.hint": "音频电平的增益倍数。更高值使 LED 对较安静的声音也有反应。",
+ "color_strip.audio.smoothing": "平滑:",
+ "color_strip.audio.smoothing.hint": "帧间时间平滑。更高值产生更平滑但反应较慢的视觉效果。",
+ "color_strip.audio.palette": "调色板:",
+ "color_strip.audio.palette.hint": "用于频谱条或节拍脉冲着色的调色板。",
+ "color_strip.audio.color": "基础颜色:",
+ "color_strip.audio.color.hint": "VU 表条的低电平颜色。",
+ "color_strip.audio.color_peak": "峰值颜色:",
+ "color_strip.audio.color_peak.hint": "VU 表条顶部的高电平颜色。",
+ "color_strip.audio.mirror": "镜像:",
+ "color_strip.audio.mirror.hint": "从中心向外镜像频谱:低音在中间,高音在两端。",
+ "color_strip.effect.type": "效果类型:",
+ "color_strip.effect.type.hint": "选择程序化算法。",
+ "color_strip.effect.fire": "火焰",
+ "color_strip.effect.fire.desc": "模拟带热量扩散的上升火焰的元胞自动机",
+ "color_strip.effect.meteor": "流星",
+ "color_strip.effect.meteor.desc": "明亮头部沿灯带移动,带指数衰减的尾迹",
+ "color_strip.effect.plasma": "等离子",
+ "color_strip.effect.plasma.desc": "映射到调色板的重叠正弦波 — 经典演示场景效果",
+ "color_strip.effect.noise": "噪声",
+ "color_strip.effect.noise.desc": "滚动的分形值噪声映射到调色板",
+ "color_strip.effect.aurora": "极光",
+ "color_strip.effect.aurora.desc": "漂移和混合的分层噪声带 — 北极光风格",
+ "color_strip.effect.speed": "速度:",
+ "color_strip.effect.speed.hint": "效果动画的速度倍数(0.1 = 非常慢,10.0 = 非常快)。",
+ "color_strip.effect.palette": "调色板:",
+ "color_strip.effect.palette.hint": "用于将效果值映射到 RGB 颜色的调色板。",
+ "color_strip.effect.color": "流星颜色:",
+ "color_strip.effect.color.hint": "流星效果的头部颜色。",
+ "color_strip.effect.intensity": "强度:",
+ "color_strip.effect.intensity.hint": "效果强度 — 控制火花率(火焰)、尾迹衰减(流星)或亮度范围(极光)。",
+ "color_strip.effect.scale": "比例:",
+ "color_strip.effect.scale.hint": "空间比例 — 波频率(等离子)、缩放级别(噪声)或带宽(极光)。",
+ "color_strip.effect.mirror": "镜像:",
+ "color_strip.effect.mirror.hint": "反弹模式 — 流星在灯带末端反转方向而不是循环。",
+ "color_strip.palette.fire": "火焰",
+ "color_strip.palette.ocean": "海洋",
+ "color_strip.palette.lava": "熔岩",
+ "color_strip.palette.forest": "森林",
+ "color_strip.palette.rainbow": "彩虹",
+ "color_strip.palette.aurora": "极光",
+ "color_strip.palette.sunset": "日落",
+ "color_strip.palette.ice": "冰",
+ "audio_source.title": "音频源",
+ "audio_source.group.multichannel": "多声道",
+ "audio_source.group.mono": "单声道",
+ "audio_source.add": "添加音频源",
+ "audio_source.add.multichannel": "添加多声道源",
+ "audio_source.add.mono": "添加单声道源",
+ "audio_source.edit": "编辑音频源",
+ "audio_source.edit.multichannel": "编辑多声道源",
+ "audio_source.edit.mono": "编辑单声道源",
+ "audio_source.name": "名称:",
+ "audio_source.name.placeholder": "系统音频",
+ "audio_source.name.hint": "此音频源的描述性名称",
+ "audio_source.type": "类型:",
+ "audio_source.type.hint": "多声道从物理音频设备采集所有通道。单声道从多声道源提取单个通道。",
+ "audio_source.type.multichannel": "多声道",
+ "audio_source.type.mono": "单声道",
+ "audio_source.device": "音频设备:",
+ "audio_source.device.hint": "音频输入源。回环设备采集系统音频输出;输入设备采集麦克风或线路输入。",
+ "audio_source.refresh_devices": "刷新设备",
+ "audio_source.parent": "父源:",
+ "audio_source.parent.hint": "要从中提取通道的多声道源",
+ "audio_source.channel": "通道:",
+ "audio_source.channel.hint": "从多声道源提取哪个音频通道",
+ "audio_source.channel.mono": "单声道(左+右混合)",
+ "audio_source.channel.left": "左",
+ "audio_source.channel.right": "右",
+ "audio_source.description": "描述(可选):",
+ "audio_source.description.placeholder": "描述此音频源...",
+ "audio_source.description.hint": "关于此音频源的可选说明",
+ "audio_source.created": "音频源已创建",
+ "audio_source.updated": "音频源已更新",
+ "audio_source.deleted": "音频源已删除",
+ "audio_source.delete.confirm": "确定要删除此音频源吗?",
+ "audio_source.error.name_required": "请输入名称",
+ "audio_source.audio_template": "音频模板:",
+ "audio_source.audio_template.hint": "定义此设备使用哪个引擎和设置的音频采集模板",
+ "audio_source.test": "测试",
+ "audio_source.test.title": "测试音频源",
+ "audio_source.test.rms": "RMS",
+ "audio_source.test.peak": "峰值",
+ "audio_source.test.beat": "节拍",
+ "audio_source.test.connecting": "连接中...",
+ "audio_source.test.error": "音频测试失败",
+ "audio_template.test": "测试",
+ "audio_template.test.title": "测试音频模板",
+ "audio_template.test.device": "音频设备:",
+ "audio_template.test.device.hint": "选择测试期间要采集的音频设备",
+ "audio_template.test.run": "运行",
+ "audio_template.title": "音频模板",
+ "audio_template.add": "添加音频模板",
+ "audio_template.edit": "编辑音频模板",
+ "audio_template.name": "模板名称:",
+ "audio_template.name.placeholder": "我的音频模板",
+ "audio_template.description.label": "描述(可选):",
+ "audio_template.description.placeholder": "描述此模板...",
+ "audio_template.engine": "音频引擎:",
+ "audio_template.engine.hint": "选择要使用的音频采集后端。WASAPI 仅限 Windows 并支持回环。Sounddevice 支持跨平台。",
+ "audio_template.engine.unavailable": "不可用",
+ "audio_template.engine.unavailable.hint": "此引擎在您的系统上不可用",
+ "audio_template.config": "配置",
+ "audio_template.config.show": "显示配置",
+ "audio_template.created": "音频模板已创建",
+ "audio_template.updated": "音频模板已更新",
+ "audio_template.deleted": "音频模板已删除",
+ "audio_template.delete.confirm": "确定要删除此音频模板吗?",
+ "audio_template.error.load": "加载音频模板失败",
+ "audio_template.error.engines": "加载音频引擎失败",
+ "audio_template.error.required": "请填写所有必填项",
+ "audio_template.error.delete": "删除音频模板失败",
+ "streams.group.value": "值源",
+ "streams.group.sync": "同步时钟",
+ "tree.group.picture": "图片源",
+ "tree.group.capture": "屏幕采集",
+ "tree.group.static": "静态",
+ "tree.group.processing": "已处理",
+ "tree.group.strip": "色带",
+ "tree.group.audio": "音频",
+ "tree.group.utility": "工具",
+ "tree.leaf.sources": "源",
+ "tree.leaf.engine_templates": "引擎模板",
+ "tree.leaf.images": "图片",
+ "tree.leaf.video": "视频",
+ "tree.leaf.filter_templates": "滤镜模板",
+ "tree.leaf.processing_templates": "处理模板",
+ "tree.leaf.templates": "模板",
+ "value_source.group.title": "值源",
+ "value_source.select_type": "选择值源类型",
+ "value_source.add": "添加值源",
+ "value_source.edit": "编辑值源",
+ "value_source.name": "名称:",
+ "value_source.name.placeholder": "亮度脉冲",
+ "value_source.name.hint": "此值源的描述性名称",
+ "value_source.type": "类型:",
+ "value_source.type.hint": "静态输出固定值。动画循环波形。音频响应声音输入。自适应类型根据时间或场景内容自动调节亮度。",
+ "value_source.type.static": "静态",
+ "value_source.type.static.desc": "固定输出值",
+ "value_source.type.animated": "动画",
+ "value_source.type.animated.desc": "循环波形变化",
+ "value_source.type.audio": "音频",
+ "value_source.type.audio.desc": "响应声音输入",
+ "value_source.type.adaptive_time": "自适应(时间)",
+ "value_source.type.adaptive_time.desc": "按时间自动调节",
+ "value_source.type.adaptive_scene": "自适应(场景)",
+ "value_source.type.adaptive_scene.desc": "按场景内容调节",
+ "value_source.type.daylight": "日光周期",
+ "value_source.type.daylight.desc": "亮度跟随日夜周期",
+ "value_source.daylight.speed": "速度:",
+ "value_source.daylight.speed.hint": "周期速度倍率。1.0 = 完整日夜周期约4分钟。",
+ "value_source.daylight.use_real_time": "使用实时:",
+ "value_source.daylight.use_real_time.hint": "启用后,亮度跟随实际时间。速度设置将被忽略。",
+ "value_source.daylight.enable_real_time": "跟随系统时钟",
+ "value_source.daylight.latitude": "纬度:",
+ "value_source.daylight.latitude.hint": "地理纬度(-90到90)。影响实时模式下的日出/日落时间。",
+ "value_source.daylight.real_time": "实时",
+ "value_source.daylight.speed_label": "速度",
+ "value_source.value": "值:",
+ "value_source.value.hint": "固定输出值(0.0 = 关闭,1.0 = 最大亮度)",
+ "value_source.waveform": "波形:",
+ "value_source.waveform.hint": "亮度动画循环的形状",
+ "value_source.waveform.sine": "正弦",
+ "value_source.waveform.triangle": "三角",
+ "value_source.waveform.square": "方波",
+ "value_source.waveform.sawtooth": "锯齿",
+ "value_source.speed": "速度(周期/分):",
+ "value_source.speed.hint": "每分钟周期数 — 波形重复的速度(1 = 非常慢,120 = 非常快)",
+ "value_source.min_value": "最小值:",
+ "value_source.min_value.hint": "波形周期的最小输出",
+ "value_source.max_value": "最大值:",
+ "value_source.max_value.hint": "波形周期的最大输出",
+ "value_source.audio_source": "音频源:",
+ "value_source.audio_source.hint": "要读取音频电平的音频源(多声道或单声道)",
+ "value_source.mode": "模式:",
+ "value_source.mode.hint": "RMS 测量平均音量。峰值跟踪最响的时刻。节拍在节奏上触发。",
+ "value_source.mode.rms": "RMS(音量)",
+ "value_source.mode.peak": "峰值",
+ "value_source.mode.beat": "节拍",
+ "value_source.mode.rms.desc": "平均音量水平",
+ "value_source.mode.peak.desc": "最响时刻追踪",
+ "value_source.mode.beat.desc": "节奏脉冲检测",
+ "value_source.auto_gain": "自动增益:",
+ "value_source.auto_gain.hint": "自动归一化音频电平,使输出使用完整范围,无论输入音量大小",
+ "value_source.auto_gain.enable": "启用自动增益",
+ "value_source.sensitivity": "灵敏度:",
+ "value_source.sensitivity.hint": "音频信号的增益倍数(越高反应越灵敏)",
+ "value_source.scene_sensitivity.hint": "亮度信号的增益倍数(越高对亮度变化越敏感)",
+ "value_source.smoothing": "平滑:",
+ "value_source.smoothing.hint": "时间平滑(0 = 即时响应,1 = 非常平滑/缓慢)",
+ "value_source.audio_min_value": "最小值:",
+ "value_source.audio_min_value.hint": "音频静默时的输出(例如 0.3 = 30% 亮度下限)",
+ "value_source.audio_max_value": "最大值:",
+ "value_source.audio_max_value.hint": "最大音频电平时的输出",
+ "value_source.schedule": "计划:",
+ "value_source.schedule.hint": "定义至少 2 个时间点。亮度在各点之间线性插值,午夜循环。",
+ "value_source.schedule.add": "+ 添加时间点",
+ "value_source.schedule.points": "个时间点",
+ "value_source.picture_source": "图片源:",
+ "value_source.picture_source.hint": "将分析其帧以获取平均亮度的图片源。",
+ "value_source.scene_behavior": "行为:",
+ "value_source.scene_behavior.hint": "互补:暗场景 = 高亮度(适合环境背光)。匹配:亮场景 = 高亮度。",
+ "value_source.scene_behavior.complement": "互补(暗 → 亮)",
+ "value_source.scene_behavior.match": "匹配(亮 → 亮)",
+ "value_source.adaptive_min_value": "最小值:",
+ "value_source.adaptive_min_value.hint": "最小输出亮度",
+ "value_source.adaptive_max_value": "最大值:",
+ "value_source.adaptive_max_value.hint": "最大输出亮度",
+ "value_source.error.schedule_min": "计划至少需要 2 个时间点",
+ "value_source.description": "描述(可选):",
+ "value_source.description.placeholder": "描述此值源...",
+ "value_source.description.hint": "关于此值源的可选说明",
+ "value_source.created": "值源已创建",
+ "value_source.updated": "值源已更新",
+ "value_source.deleted": "值源已删除",
+ "value_source.delete.confirm": "确定要删除此值源吗?",
+ "value_source.error.name_required": "请输入名称",
+ "value_source.test": "测试",
+ "value_source.test.title": "测试值源",
+ "value_source.test.connecting": "连接中...",
+ "value_source.test.error": "连接失败",
+ "value_source.test.current": "当前",
+ "value_source.test.min": "最小",
+ "value_source.test.max": "最大",
+ "test.frames": "帧数",
+ "test.fps": "帧率",
+ "test.avg_capture": "平均",
+ "targets.brightness_vs": "亮度源:",
+ "targets.brightness_vs.hint": "可选的值源,每帧动态控制亮度(覆盖设备亮度)",
+ "targets.brightness_vs.none": "无(设备亮度)",
+ "targets.min_brightness_threshold": "最低亮度阈值:",
+ "targets.min_brightness_threshold.hint": "当有效输出亮度(像素亮度 × 设备/源亮度)低于此值时,LED完全关闭(0 = 禁用)",
+ "targets.adaptive_fps": "自适应FPS:",
+ "targets.adaptive_fps.hint": "当设备无响应时自动降低发送速率,稳定后逐步恢复。推荐用于信号较弱的WiFi设备。",
+ "targets.protocol": "协议:",
+ "targets.protocol.hint": "DDP通过快速UDP发送像素(推荐)。HTTP使用JSON API——较慢但可靠,限制约500个LED。",
+ "targets.protocol.ddp": "DDP (UDP)",
+ "targets.protocol.ddp.desc": "快速UDP数据包 - 推荐",
+ "targets.protocol.http": "HTTP",
+ "targets.protocol.http.desc": "JSON API - 较慢,≤500 LED",
+ "targets.protocol.serial": "串口",
+ "search.open": "搜索 (Ctrl+K)",
+ "search.placeholder": "搜索实体... (Ctrl+K)",
+ "search.loading": "加载中...",
+ "search.no_results": "未找到结果",
+ "search.group.devices": "设备",
+ "search.group.targets": "LED 目标",
+ "search.group.kc_targets": "关键颜色目标",
+ "search.group.css": "色带源",
+ "search.group.automations": "自动化",
+ "search.group.streams": "图片流",
+ "search.group.capture_templates": "采集模板",
+ "search.group.pp_templates": "后处理模板",
+ "search.group.pattern_templates": "图案模板",
+ "search.group.audio": "音频源",
+ "search.group.value": "值源",
+ "search.group.scenes": "场景预设",
+ "search.group.cspt": "色带处理模板",
+ "search.group.sync_clocks": "同步时钟",
+ "search.group.actions": "操作",
+ "search.action.start": "启动",
+ "search.action.stop": "停止",
+ "search.action.activate": "激活",
+ "search.action.enable": "启用",
+ "search.action.disable": "禁用",
+ "settings.backup.label": "备份配置",
+ "settings.backup.hint": "将所有配置(设备、目标、流、模板、自动化)下载为单个 JSON 文件。",
+ "settings.backup.button": "下载备份",
+ "settings.backup.success": "备份下载成功",
+ "settings.backup.error": "备份下载失败",
+ "settings.restore.label": "恢复配置",
+ "settings.restore.hint": "上传之前下载的备份文件以替换所有配置。服务器将自动重启。",
+ "settings.restore.button": "从备份恢复",
+ "settings.restore.confirm": "这将替换所有配置并重启服务器。确定继续吗?",
+ "settings.restore.success": "配置已恢复",
+ "settings.restore.error": "恢复失败",
+ "settings.restore.restarting": "服务器正在重启...",
+ "settings.restore.restart_timeout": "服务器未响应。请手动刷新页面。",
+ "settings.restart_server": "重启服务器",
+ "settings.restart_confirm": "重启服务器?活跃的目标将被停止。",
+ "settings.restarting": "正在重启服务器...",
+ "settings.button.close": "关闭",
+ "settings.log_level.label": "日志级别",
+ "settings.log_level.hint": "实时更改服务器日志详细程度。DEBUG 显示最多细节;CRITICAL 仅显示致命错误。",
+ "settings.log_level.save": "应用",
+ "settings.log_level.saved": "日志级别已更改",
+ "settings.log_level.save_error": "更改日志级别失败",
+ "settings.log_level.desc.debug": "详细开发输出",
+ "settings.log_level.desc.info": "正常运行消息",
+ "settings.log_level.desc.warning": "潜在问题",
+ "settings.log_level.desc.error": "仅显示错误",
+ "settings.log_level.desc.critical": "仅显示致命错误",
+ "settings.auto_backup.label": "自动备份",
+ "settings.auto_backup.hint": "自动定期创建所有配置的备份。当达到最大数量时,旧备份会被自动清理。",
+ "settings.auto_backup.enable": "启用自动备份",
+ "settings.auto_backup.interval_label": "间隔",
+ "settings.auto_backup.max_label": "最大备份数",
+ "settings.auto_backup.save": "保存设置",
+ "settings.auto_backup.saved": "自动备份设置已保存",
+ "settings.auto_backup.save_error": "保存自动备份设置失败",
+ "settings.auto_backup.last_backup": "上次备份",
+ "settings.auto_backup.never": "从未",
+ "settings.saved_backups.label": "已保存的备份",
+ "settings.saved_backups.hint": "存储在服务器上的自动备份文件。下载到本地保存,或删除以释放空间。",
+ "settings.saved_backups.empty": "没有已保存的备份",
+ "settings.saved_backups.restore": "恢复",
+ "settings.saved_backups.download": "下载",
+ "settings.saved_backups.delete": "删除",
+ "settings.saved_backups.delete_confirm": "删除此备份文件?",
+ "settings.saved_backups.delete_error": "删除备份失败",
+ "settings.saved_backups.type.auto": "自动",
+ "settings.saved_backups.type.manual": "手动",
+ "settings.mqtt.label": "MQTT",
+ "settings.mqtt.hint": "配置 MQTT 代理连接,用于自动化条件和触发器。",
+ "settings.mqtt.enabled": "启用 MQTT",
+ "settings.mqtt.host_label": "代理主机",
+ "settings.mqtt.port_label": "端口",
+ "settings.mqtt.username_label": "用户名",
+ "settings.mqtt.password_label": "密码",
+ "settings.mqtt.password_set_hint": "已设置密码 — 留空以保留",
+ "settings.mqtt.client_id_label": "客户端 ID",
+ "settings.mqtt.base_topic_label": "基础主题",
+ "settings.mqtt.save": "保存 MQTT 设置",
+ "settings.mqtt.saved": "MQTT 设置已保存",
+ "settings.mqtt.save_error": "保存 MQTT 设置失败",
+ "settings.mqtt.error_host_required": "代理主机不能为空",
+ "settings.logs.label": "服务器日志",
+ "settings.logs.hint": "实时查看服务器日志。使用过滤器显示所需的日志级别。",
+ "settings.logs.connect": "连接",
+ "settings.logs.disconnect": "断开",
+ "settings.logs.clear": "清除",
+ "settings.logs.error": "日志查看器连接失败",
+ "settings.logs.filter.all": "所有级别",
+ "settings.logs.filter.info": "Info+",
+ "settings.logs.filter.warning": "Warning+",
+ "settings.logs.filter.error": "仅错误",
+ "settings.logs.filter.all_desc": "显示所有日志消息",
+ "settings.logs.filter.info_desc": "Info、警告和错误",
+ "settings.logs.filter.warning_desc": "仅警告和错误",
+ "settings.logs.filter.error_desc": "仅错误",
+ "device.error.power_off_failed": "关闭设备失败",
+ "device.error.remove_failed": "移除设备失败",
+ "device.error.settings_load_failed": "加载设备设置失败",
+ "device.error.brightness": "更新亮度失败",
+ "device.error.required": "请填写所有字段",
+ "device.error.update": "更新设备失败",
+ "device.error.save": "保存设置失败",
+ "device.error.clone_failed": "克隆设备失败",
+ "device_discovery.error.fill_all_fields": "请填写所有字段",
+ "device_discovery.added": "设备添加成功",
+ "device_discovery.error.add_failed": "添加设备失败",
+ "calibration.error.load_failed": "加载校准失败",
+ "calibration.error.css_load_failed": "加载色带源失败",
+ "calibration.error.test_toggle_failed": "切换测试边缘失败",
+ "calibration.error.save_failed": "保存校准失败",
+ "calibration.error.led_count_mismatch": "LED总数必须等于设备LED数量",
+ "calibration.error.led_count_exceeded": "校准的LED超过了LED总数",
+ "calibration.mode.simple": "简单",
+ "calibration.mode.advanced": "高级",
+ "calibration.switch_to_advanced": "切换到高级模式",
+ "calibration.advanced.title": "高级校准",
+ "calibration.advanced.switch_to_simple": "切换到简单模式",
+ "calibration.advanced.lines_title": "线段",
+ "calibration.advanced.canvas_hint": "拖动显示器重新排列。点击边缘选择线段。滚动缩放,拖动空白区域平移。",
+ "calibration.advanced.reset_view": "重置视图",
+ "calibration.advanced.line_properties": "线段属性",
+ "calibration.advanced.picture_source": "来源:",
+ "calibration.advanced.picture_source.hint": "此线段采样的图片来源(显示器)",
+ "calibration.advanced.edge": "边缘:",
+ "calibration.advanced.edge.hint": "从屏幕哪条边缘采样像素",
+ "calibration.advanced.led_count": "LED数:",
+ "calibration.advanced.led_count.hint": "映射到此线段的LED数量",
+ "calibration.advanced.span_start": "起始位置:",
+ "calibration.advanced.span_start.hint": "沿边缘开始采样的位置(0 = 起点,1 = 终点)。用于仅覆盖边缘的一部分。",
+ "calibration.advanced.span_end": "结束位置:",
+ "calibration.advanced.span_end.hint": "沿边缘结束采样的位置(0 = 起点,1 = 终点)。与起始位置一起定义活动区域。",
+ "calibration.advanced.border_width": "深度(像素):",
+ "calibration.advanced.border_width.hint": "从边缘向内采样多少像素。较大的值会捕获更多屏幕内部区域。",
+ "calibration.advanced.reverse": "反转",
+ "calibration.advanced.no_lines_warning": "请至少添加一条线段",
+ "dashboard.error.automation_toggle_failed": "切换自动化失败",
+ "dashboard.error.start_failed": "启动处理失败",
+ "dashboard.error.stop_failed": "停止处理失败",
+ "dashboard.error.stop_all": "停止所有目标失败",
+ "target.error.editor_open_failed": "打开目标编辑器失败",
+ "target.error.start_failed": "启动目标失败",
+ "target.error.stop_failed": "停止目标失败",
+ "target.error.clone_failed": "克隆目标失败",
+ "target.error.delete_failed": "删除目标失败",
+ "targets.stop_all.button": "全部停止",
+ "targets.stop_all.none_running": "当前没有运行中的目标",
+ "targets.stop_all.stopped": "已停止 {count} 个目标",
+ "targets.stop_all.error": "停止目标失败",
+ "audio_source.error.load": "加载音频源失败",
+ "audio_template.error.clone_failed": "克隆音频模板失败",
+ "value_source.error.load": "加载数值源失败",
+ "color_strip.error.editor_open_failed": "打开色带编辑器失败",
+ "color_strip.error.clone_failed": "克隆色带源失败",
+ "color_strip.error.delete_failed": "删除色带源失败",
+ "pattern.error.editor_open_failed": "打开图案模板编辑器失败",
+ "pattern.error.clone_failed": "克隆图案模板失败",
+ "pattern.error.delete_failed": "删除图案模板失败",
+ "pattern.error.capture_bg_failed": "捕获背景失败",
+ "stream.error.clone_picture_failed": "克隆图片源失败",
+ "stream.error.clone_capture_failed": "克隆捕获模板失败",
+ "stream.error.clone_pp_failed": "克隆后处理模板失败",
+ "kc_target.error.editor_open_failed": "打开关键颜色编辑器失败",
+ "kc_target.error.clone_failed": "克隆关键颜色目标失败",
+ "kc_target.error.delete_failed": "删除关键颜色目标失败",
+ "theme.switched.dark": "已切换到深色主题",
+ "theme.switched.light": "已切换到浅色主题",
+ "accent.color.updated": "强调色已更新",
+ "search.footer": "↑↓ 导航 · Enter 选择 · Esc 关闭",
+ "sync_clock.group.title": "同步时钟",
+ "sync_clock.add": "添加同步时钟",
+ "sync_clock.edit": "编辑同步时钟",
+ "sync_clock.name": "名称:",
+ "sync_clock.name.placeholder": "主动画时钟",
+ "sync_clock.name.hint": "此同步时钟的描述性名称",
+ "sync_clock.speed": "速度:",
+ "sync_clock.speed.hint": "所有关联源的动画速度倍率。1.0 = 正常,2.0 = 双倍,0.5 = 半速。",
+ "sync_clock.description": "描述(可选):",
+ "sync_clock.description.placeholder": "可选描述",
+ "sync_clock.description.hint": "关于此时钟用途的可选备注",
+ "sync_clock.status.running": "运行中",
+ "sync_clock.status.paused": "已暂停",
+ "sync_clock.action.pause": "暂停",
+ "sync_clock.action.resume": "恢复",
+ "sync_clock.action.reset": "重置",
+ "sync_clock.error.name_required": "时钟名称为必填项",
+ "sync_clock.error.load": "加载同步时钟失败",
+ "sync_clock.created": "同步时钟已创建",
+ "sync_clock.updated": "同步时钟已更新",
+ "sync_clock.deleted": "同步时钟已删除",
+ "sync_clock.paused": "时钟已暂停",
+ "sync_clock.resumed": "时钟已恢复",
+ "sync_clock.reset_done": "时钟已重置为零",
+ "sync_clock.delete.confirm": "删除此同步时钟?关联的源将失去同步并以默认速度运行。",
+ "sync_clock.elapsed": "已用时间",
+ "color_strip.clock": "同步时钟:",
+ "color_strip.clock.hint": "关联同步时钟以在多个源之间同步动画。速度在时钟上控制。",
+ "graph.title": "图表",
+ "graph.fit_all": "显示所有节点",
+ "graph.zoom_in": "放大",
+ "graph.zoom_out": "缩小",
+ "graph.search": "搜索节点",
+ "graph.search_placeholder": "搜索实体...",
+ "graph.legend": "图例",
+ "graph.minimap": "小地图",
+ "graph.relayout": "重新布局",
+ "graph.empty": "暂无实体",
+ "graph.empty.hint": "创建设备、源和目标后即可在此查看。",
+ "graph.disconnect": "断开连接",
+ "graph.connection_updated": "连接已更新",
+ "graph.connection_failed": "更新连接失败",
+ "graph.connection_removed": "连接已移除",
+ "graph.disconnect_failed": "断开连接失败",
+ "graph.relayout_confirm": "重置所有手动节点位置并重新布局图表?",
+ "graph.fullscreen": "切换全屏",
+ "graph.add_entity": "添加实体",
+ "graph.color_picker": "节点颜色",
+ "graph.filter": "筛选节点",
+ "graph.filter_placeholder": "按名称筛选...",
+ "graph.filter_clear": "清除筛选",
+ "graph.filter_running": "运行中",
+ "graph.filter_stopped": "已停止",
+ "graph.filter_types": "类型",
+ "graph.filter_group.capture": "捕获",
+ "graph.filter_group.strip": "色带",
+ "graph.filter_group.audio": "音频",
+ "graph.filter_group.targets": "目标",
+ "graph.filter_group.other": "其他",
+ "graph.bulk_delete_confirm": "删除 {count} 个选中的实体?",
+ "graph.nothing_to_undo": "没有可撤销的操作",
+ "graph.nothing_to_redo": "没有可重做的操作",
+ "graph.help_title": "键盘快捷键",
+ "graph.help.search": "搜索",
+ "graph.help.filter": "筛选",
+ "graph.help.add": "添加实体",
+ "graph.help.shortcuts": "快捷键",
+ "graph.help.delete": "删除 / 断开",
+ "graph.help.select_all": "全选",
+ "graph.help.undo": "撤销",
+ "graph.help.redo": "重做",
+ "graph.help.fullscreen": "全屏",
+ "graph.help.deselect": "取消选择",
+ "graph.help.navigate": "节点导航",
+ "graph.help.click": "单击",
+ "graph.help.click_desc": "选择节点",
+ "graph.help.dblclick": "双击",
+ "graph.help.dblclick_desc": "缩放到节点",
+ "graph.help.shift_click": "Shift+单击",
+ "graph.help.shift_click_desc": "多选",
+ "graph.help.shift_drag": "Shift+拖拽",
+ "graph.help.shift_drag_desc": "框选",
+ "graph.help.drag_node": "拖拽节点",
+ "graph.help.drag_node_desc": "重新定位",
+ "graph.help.drag_port": "拖拽端口",
+ "graph.help.drag_port_desc": "连接实体",
+ "graph.help.right_click": "右键边线",
+ "graph.help.right_click_desc": "断开连接",
+ "graph.tooltip.fps": "帧率",
+ "graph.tooltip.errors": "错误",
+ "graph.tooltip.uptime": "运行时间",
+ "automation.enabled": "自动化已启用",
+ "automation.disabled": "自动化已禁用",
+ "scene_preset.activated": "预设已激活",
+ "scene_preset.used_by": "被 %d 个自动化使用",
+ "settings.api_keys.label": "API 密钥",
+ "settings.api_keys.hint": "API 密钥在服务器配置文件 (config.yaml) 中定义。编辑文件并重启服务器以应用更改。",
+ "settings.api_keys.empty": "未配置 API 密钥",
+ "settings.api_keys.load_error": "加载 API 密钥失败",
+ "settings.partial.label": "部分导出 / 导入",
+ "settings.partial.hint": "导出或导入单个实体类型。导入会替换或合并现有数据并重启服务器。",
+ "settings.partial.store.devices": "设备",
+ "settings.partial.store.output_targets": "LED 目标",
+ "settings.partial.store.color_strip_sources": "色带",
+ "settings.partial.store.picture_sources": "图像源",
+ "settings.partial.store.audio_sources": "音频源",
+ "settings.partial.store.audio_templates": "音频模板",
+ "settings.partial.store.capture_templates": "捕获模板",
+ "settings.partial.store.postprocessing_templates": "后处理模板",
+ "settings.partial.store.color_strip_processing_templates": "CSS 处理模板",
+ "settings.partial.store.pattern_templates": "图案模板",
+ "settings.partial.store.value_sources": "值源",
+ "settings.partial.store.sync_clocks": "同步时钟",
+ "settings.partial.store.automations": "自动化",
+ "settings.partial.store.scene_presets": "场景预设",
+ "settings.partial.export_button": "导出",
+ "settings.partial.import_button": "从文件导入",
+ "settings.partial.merge_label": "合并(添加/覆盖,保留现有)",
+ "settings.partial.export_success": "导出成功",
+ "settings.partial.export_error": "导出失败",
+ "settings.partial.import_success": "导入成功",
+ "settings.partial.import_error": "导入失败",
+ "settings.partial.import_confirm_replace": "这将替换所有 {store} 数据并重启服务器。继续吗?",
+ "settings.partial.import_confirm_merge": "这将合并 {store} 数据并重启服务器。继续吗?",
+ "section.empty.devices": "暂无设备。点击 + 添加。",
+ "section.empty.targets": "暂无 LED 目标。点击 + 添加。",
+ "section.empty.kc_targets": "暂无键色目标。点击 + 添加。",
+ "section.empty.pattern_templates": "暂无图案模板。点击 + 添加。",
+ "section.empty.picture_sources": "暂无源。点击 + 添加。",
+ "section.empty.capture_templates": "暂无捕获模板。点击 + 添加。",
+ "section.empty.pp_templates": "暂无后处理模板。点击 + 添加。",
+ "section.empty.audio_sources": "暂无音频源。点击 + 添加。",
+ "section.empty.audio_templates": "暂无音频模板。点击 + 添加。",
+ "section.empty.color_strips": "暂无色带。点击 + 添加。",
+ "section.empty.value_sources": "暂无值源。点击 + 添加。",
+ "section.empty.sync_clocks": "暂无同步时钟。点击 + 添加。",
+ "section.empty.cspt": "暂无 CSS 处理模板。点击 + 添加。",
+ "section.empty.automations": "暂无自动化。点击 + 添加。",
+ "section.empty.scenes": "暂无场景预设。点击 + 添加。",
+ "bulk.select": "选择",
+ "bulk.cancel": "取消",
+ "bulk.selected_count.one": "已选 {count} 项",
+ "bulk.selected_count.other": "已选 {count} 项",
+ "bulk.select_all": "全选",
+ "bulk.deselect_all": "取消全选",
+ "bulk.delete": "删除",
+ "bulk.start": "启动",
+ "bulk.stop": "停止",
+ "bulk.enable": "启用",
+ "bulk.disable": "禁用",
+ "bulk.confirm_delete.one": "删除 {count} 项?",
+ "bulk.confirm_delete.other": "删除 {count} 项?",
+ "color_strip": {
+ "notification": {
+ "search_apps": "搜索通知应用…"
+ }
+ }
+}
\ No newline at end of file
diff --git a/server/src/wled_controller/templates/modals/css-editor.html b/server/src/wled_controller/templates/modals/css-editor.html
index b65844f..b9c91f0 100644
--- a/server/src/wled_controller/templates/modals/css-editor.html
+++ b/server/src/wled_controller/templates/modals/css-editor.html
@@ -460,10 +460,6 @@
-