diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index d5f2c0cba..1a47ee6f8 100644 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -14,6 +14,7 @@ import ptBR from './locales/pt-BR'; import zhCN from './locales/zh-CN'; import zhTW from './locales/zh-TW'; import tr from './locales/tr'; +import ru from './locales/ru'; const resources = { en: { translation: en }, @@ -27,9 +28,10 @@ const resources = { 'zh-CN': { translation: zhCN }, 'zh-TW': { translation: zhTW }, tr: { translation: tr }, + ru: { translation: ru }, }; -const SUPPORTED_LNGS = ['en', 'de', 'es', 'fr', 'ja', 'it', 'ko', 'pt-BR', 'tr', 'zh-CN', 'zh-TW']; +const SUPPORTED_LNGS = ['en', 'de', 'es', 'fr', 'ja', 'it', 'ko', 'pt-BR', 'ru', 'tr', 'zh-CN', 'zh-TW']; const APPLIANCE_CONSUMED_KEY = 'bambuddy_appliance_locale_consumed'; i18n @@ -107,4 +109,5 @@ export const availableLanguages = [ { code: 'zh-CN', name: 'Chinese (Simplified)', nativeName: '简体中文' }, { code: 'zh-TW', name: 'Chinese (Traditional)', nativeName: '繁體中文' }, { code: 'tr', name: 'Turkish', nativeName: 'Türkçe' }, + { code: 'ru', name: 'Russian', nativeName: 'Русский' }, ]; diff --git a/frontend/src/i18n/locales/ru.ts b/frontend/src/i18n/locales/ru.ts new file mode 100644 index 000000000..e9d17867b --- /dev/null +++ b/frontend/src/i18n/locales/ru.ts @@ -0,0 +1,6422 @@ +/** + * Russian locale — complete translation. + */ +export default { + nav: { + printers: 'Принтеры', + archives: 'Архив', + queue: 'Очередь печати', + stats: 'Статистика', + profiles: 'Профили', + maintenance: 'Обслуживание', + projects: 'Проекты', + inventory: 'Филамент', + files: 'Файловый менеджер', + makerworld: 'MakerWorld', + notifications: 'Уведомления', + settings: 'Настройки', + system: 'Система', + collapseSidebar: 'Свернуть боковую панель', + expandSidebar: 'Развернуть боковую панель', + update: 'Обновить', + updateAvailable: 'Доступно обновление: v{{version}}', + updateAvailableBanner: 'Доступна версия {{version}}!', + viewUpdate: 'Посмотреть обновление', + viewOnGithub: 'Открыть на GitHub', + keyboardShortcuts: 'Горячие клавиши (?)', + switchToLight: 'Включить светлую тему', + switchToDark: 'Включить тёмную тему', + switchToSystem: 'Использовать системную тему', + smartSwitches: 'Умные выключатели', + logout: 'Выйти', + installApp: 'Установить приложение', + installAppSuccess: 'Bambuddy установлен', + }, + common: { + save: 'Сохранить', + saving: 'Сохранение...', + cancel: 'Отмена', + delete: 'Удалить', + edit: 'Изменить', + add: 'Добавить', + close: 'Закрыть', + confirm: 'Подтвердить', + loading: 'Загрузка...', + error: 'Ошибка', + errorLoading: 'Не удалось загрузить данные', + retry: 'Повторить', + success: 'Готово', + warning: 'Предупреждение', + enabled: 'Включено', + disabled: 'Отключено', + yes: 'Да', + no: 'Нет', + on: 'Вкл.', + off: 'Выкл.', + all: 'Все', + none: 'Нет', + search: 'Поиск', + filter: 'Фильтр', + sort: 'Сортировка', + refresh: 'Обновить', + download: 'Скачать', + upload: 'Загрузить', + uploading: 'Загрузка...', + uploadFailed: 'Ошибка загрузки', + actions: 'Действия', + status: 'Состояние', + name: 'Название', + description: 'Описание', + date: 'Дата', + time: 'Время', + hours: 'часов', + minutes: 'минут', + seconds: 'секунд', + days: 'дней', + enable: 'Включить', + disable: 'Отключить', + permissions: 'Разрешения', + noPrinters: 'Принтеры не настроены', + noData: 'Нет данных', + linkNotFound: 'Ссылка не найдена', + required: 'Обязательно', + optional: 'Необязательно', + dismiss: 'Закрыть', + apply: 'Применить', + reset: 'Сбросить', + export: 'Экспорт', + import: 'Импорт', + clear: 'Очистить', + selectAll: 'Выбрать все', + deselectAll: 'Снять выделение', + noChange: '— Без изменений —', + unchanged: 'Без изменений', + unassigned: 'Не назначено', + unknown: 'Неизвестно', + unknownError: 'Неизвестная ошибка', + today: 'Сегодня', + tomorrow: 'Завтра', + asap: 'Как можно скорее', + overdue: 'Просрочено', + now: 'Сейчас', + collapse: 'Свернуть', + expand: 'Развернуть', + previous: 'Назад', + next: 'Далее', + viewArchive: 'Открыть архив', + viewInFileManager: 'Открыть в файловом менеджере', + addedBy: 'Добавил: {{username}}', + prints: 'печатей', + more: 'ещё +{{count}}', + ascending: 'По возрастанию', + descending: 'По убыванию', + back: 'Назад', + copy: 'Копировать', + copied: 'Скопировано!', + printer: 'Принтер', + remove: 'Удалить', + type: 'Тип', + print: 'Печать', + rename: 'Переименовать', + move: 'Переместить', + create: 'Создать', + duplicate: 'Дублировать', + left: 'Левый', + right: 'Правый', + }, + printers: { + title: 'Принтеры', + addPrinter: 'Добавить принтер', + addPreflight: { + checking: 'Проверка подключения...', + warning: 'Некоторые проверки подключения не пройдены. Принтер может отображаться как отключённый. Проверьте результаты ниже, исправьте возможные проблемы или сохраните настройки как есть.', + back: 'Назад', + saveAnyway: 'Всё равно сохранить', + }, + editPrinter: 'Изменить принтер', + deletePrinter: 'Удалить принтер', + printerName: 'Название принтера', + serialNumber: 'Серийный номер', + ipAddress: 'IP-адрес / имя хоста', + accessCode: 'Код доступа', + model: 'Модель', + nozzleCount: 'Количество сопел', + autoArchive: 'Автоматически архивировать', + status: { + title: 'Статус', + available: 'Доступен', + idle: 'Ожидает', + printing: 'Печать', + paused: 'Приостановлен', + offline: 'Не в сети', + problem: 'Проблема', + error: 'Ошибка', + finished: 'Завершено', + unknown: 'Неизвестно', + }, + temperatures: { + nozzle: 'Сопло', + bed: 'Стол', + chamber: 'Камера', + }, + heaterHistory: { + title: 'История нагрева', + openLabel: 'Открыть историю нагрева', + nozzle: 'Сопло', + nozzle2: 'Сопло 2', + bed: 'Стол', + chamber: 'Камера', + error: 'Не удалось загрузить историю', + empty: 'Данные пока не записывались', + }, + progress: 'Выполнено {{percent}}%', + timeRemaining: 'Осталось {{time}}', + deleteConfirm: 'Удалить принтер «{{name}}»?', + maintenanceOk: 'Обслуживание в норме', + maintenanceWarning: '{{count}} предупреждение', + maintenanceWarning_plural: '{{count}} предупреждений', + maintenanceDue: 'Требуется: {{count}}', + maintenanceDue_plural: 'Требуется: {{count}}', + sort: { + name: 'Название', + status: 'Состояние', + model: 'Модель', + location: 'Расположение', + eta: 'Время завершения', + ascending: 'По возрастанию', + descending: 'По убыванию', + }, + cardSize: { + small: 'Маленькие карточки', + medium: 'Средние карточки', + large: 'Большие карточки', + extraLarge: 'Очень большие карточки', + }, + pageView: { + cards: 'Карточки', + camWall: 'Стена камер', + }, + camWall: { + noPrinters: 'Нет принтеров для отображения', + noSignal: 'Нет сигнала', + live: 'Онлайн', + snap: 'Снимок', + off: 'Выкл.', + summary: 'Онлайн: {{live}}, снимки: {{snap}}, всего: {{total}}', + layer: 'Слой {{cur}}/{{total}}', + timeLeft: 'Осталось {{time}}', + statusMode: { + off: 'Выкл.', + compact: 'Компактный', + full: 'Полный', + }, + settings: { + title: 'Настройки стены камер', + maxLive: 'Максимум онлайн-трансляций', + maxLiveHint: 'Сколько камер одновременно показывать в реальном времени. Остальные будут обновляться снимками.', + snapshotInterval: 'Интервал снимков, с', + snapshotIntervalHint: 'Как часто обновлять снимки камер без онлайн-трансляции.', + statusOverlay: 'Наложение состояния', + statusOverlayHint: 'Компактный режим: только состояние. Полный: прогресс, слой и оставшееся время.', + }, + }, + hideOffline: 'Скрыть принтеры не в сети', + nextAvailable: 'Ближайший доступный', + power: 'Питание', + powerOn: 'Включить питание', + offlinePrintersWithPlugs: 'Принтеры не в сети с умными розетками', + noPrintersConfigured: 'Принтеры пока не настроены', + search: 'Поиск принтеров...', + noSearchResults: 'Нет принтеров, соответствующих поиску или фильтрам', + filter: { + allStatuses: 'Все состояния', + allLocations: 'Все расположения', + }, + toolbar: { + filters: 'Фильтры', + view: 'Вид', + actions: 'Действия', + }, + readyToPrint: 'Готов к печати', + external: 'Внешняя подача', + extL: 'Внешняя, левое', + extR: 'Внешняя, правое', + deleteArchives: 'Удалить архивы печати', + noLabel: 'Без метки', + printPreview: 'Предпросмотр печати', + width: 'Ширина', + height: 'Высота', + noObjectsFound: 'Объекты не найдены', + objectsLoadedOnPrintStart: 'Объекты загрузятся после начала печати', + willBeSkipped: 'Будет пропущен', + name: 'Название', + serialCannotBeChanged: 'Серийный номер нельзя изменить', + locationHelp: 'Используется для группировки принтеров и фильтрации заданий в очереди', + wifiSignal: { + veryWeak: 'Очень слабый', + weak: 'Слабый', + fair: 'Средний', + good: 'Хороший', + excellent: 'Отличный', + }, + maintenanceUpToDate: 'Обслуживание выполнено — нажмите для просмотра', + maintenance: { + title: 'На обслуживании', + subtitle: 'Принтер приостановлен: подключение отключено, задания из очереди не назначаются, уведомления не отправляются.', + pillLabel: 'Обслуживание', + exitButton: 'Завершить обслуживание', + menuEnter: 'Перевести в режим обслуживания', + menuExit: 'Выйти из режима обслуживания', + toastEntered: 'Принтер {{name}} переведён в режим обслуживания', + toastExited: 'Принтер {{name}} снова в работе', + confirmMidPrintTitle: 'Перевести в режим обслуживания во время печати?', + confirmMidPrintMessage: 'Принтер {{name}} сейчас печатает. Режим обслуживания отключит MQTT, отслеживание прогресса и уведомление о завершении этого задания. Продолжить?', + editFieldLabel: 'Режим обслуживания', + editFieldHelp: 'Отключает для принтера MQTT, назначение заданий из очереди и уведомления. Используйте при ремонте, параллельных установках Bambuddy или временной приостановке.', + }, + chamberLightOn: 'Включить подсветку камеры', + chamberLightOff: 'Выключить подсветку камеры', + files: 'Файлы', + browseFiles: 'Открыть файлы принтера', + autoOffAfterPrint: 'Автовыключение после печати', + autoOffExecuted: 'Автовыключение выполнено — включите принтер для сброса состояния', + hmsErrors: 'Ошибки HMS', + viewHmsErrors: 'Показать ошибки HMS: {{count}}', + resume: 'Продолжить', + pause: 'Пауза', + stop: 'Стоп', + camera: 'Камера', + skipObject: 'Пропустить объект', + reconnect: 'Переподключить', + forceRefresh: 'Принудительно обновить', + forceRefreshSuccess: 'Запрошено обновление данных', + mqttDebug: 'Отладка MQTT', + printerInformation: 'Информация о принтере', + copyToClipboard: 'Копировать', + copied: 'Скопировано!', + state: 'Состояние', + wifiSignalLabel: 'Сигнал Wi‑Fi', + developerMode: 'Режим разработчика', + enabled: 'Включён', + disabled: 'Отключён', + addedOn: 'Добавлен', + sdCard: 'SD-карта', + inserted: 'Установлена', + notInserted: 'Не установлена', + totalPrintHours: 'Часов печати', + activeNozzle: 'Активное сопло: {{nozzle}}', + nozzleRack: 'Держатель сопел', + nozzleDocked: 'В держателе', + nozzleMounted: 'Установлено', + nozzleActive: 'Активно', + nozzleIdle: 'Ожидание', + nozzleDiameter: 'Диаметр', + nozzleType: 'Тип', + nozzleStatus: 'Состояние', + nozzleFilament: 'Филамент', + nozzleWear: 'Износ', + nozzleMaxTemp: 'Макс. температура', + nozzleSerial: 'Серийный номер', + nozzleHardenedSteel: 'Закалённая сталь', + nozzleStainlessSteel: 'Нержавеющая сталь', + nozzleTungstenCarbide: 'Карбид вольфрама', + nozzleFlow: 'Производительность', + nozzleHighFlow: 'Высокопоточное', + nozzleStandardFlow: 'Стандартное', + firmwareUpdate: 'Обновление прошивки', + firmwareInstructions: 'На сенсорном экране принтера откройте', + firmwareNav: 'Перейдите в раздел', + settings: 'Настройки', + firmware: 'Прошивка', + discoverPrinters: 'Найти принтеры', + searching: 'Поиск...', + manualEntry: 'Добавить вручную', + addFromCloud: 'Добавить из облака', + toast: { + printerDeleted: 'Принтер удалён', + missingSpoolAssignment: 'На принтере {{printer}} началась печать. Не назначены катушки для слотов: {{slots}}', + printerAdded: 'Принтер добавлен', + printerUpdated: 'Настройки принтера обновлены', + failedToDelete: 'Не удалось удалить принтер', + failedToAdd: 'Не удалось добавить принтер', + connectionFailedNotAdded: 'Не удалось подключиться к принтеру. Проверьте IP-адрес, серийный номер и код доступа, а также убедитесь, что включён режим «Только локальная сеть». Принтер не добавлен.', + failedToUpdate: 'Не удалось обновить настройки принтера', + commandSent: 'Команда отправлена', + failedToSendCommand: 'Не удалось отправить команду', + turnedOn: 'Питание {{name}} включено', + failedToPowerOn: 'Не удалось включить {{name}}', + scriptTriggered: 'Сценарий запущен', + printStopped: 'Печать остановлена', + printPaused: 'Печать приостановлена', + printResumed: 'Печать продолжена', + referenceDeleted: 'Эталон удалён', + detectionAreaSaved: 'Область обнаружения сохранена', + failedToRunScript: 'Не удалось запустить сценарий', + failedToStopPrint: 'Не удалось остановить печать', + failedToPausePrint: 'Не удалось приостановить печать', + failedToResumePrint: 'Не удалось продолжить печать', + failedToControlChamberLight: 'Не удалось изменить состояние подсветки камеры', + failedToSetSpeed: 'Не удалось изменить скорость печати', + failedToUpdateSetting: 'Не удалось изменить настройку', + failedToSkipObjects: 'Не удалось пропустить объекты', + failedToRereadRfid: 'Не удалось повторно считать RFID', + failedToCheckPlate: 'Не удалось проверить пластину', + failedToUpdateLabel: 'Не удалось обновить метку', + failedToDeleteReference: 'Не удалось удалить эталон', + failedToSaveDetectionArea: 'Не удалось сохранить область обнаружения', + plateCheckEnabled: 'Проверка пластины включена', + plateCheckDisabled: 'Проверка пластины отключена', + calibrationSaved: 'Калибровка сохранена', + calibrationFailed: 'Не удалось выполнить калибровку', + rfidRereadInitiated: 'Запущено повторное считывание RFID', + loadInitiated: 'Загрузка филамента…', + unloadInitiated: 'Выгрузка филамента…', + failedToLoad: 'Не удалось загрузить филамент', + failedToUnload: 'Не удалось выгрузить филамент', + }, + connection: { + connected: 'Подключён', + offline: 'Не в сети', + }, + plateStatus: { + markCleared: 'Отметить пластину как очищенную', + cleared: 'Пластина очищена', + notCleared: 'Пластина не очищена', + inUse: 'Пластина используется', + }, + queue: { + inQueue: 'В очереди: {{count}} задание', + inQueue_plural: 'В очереди: {{count}} заданий', + }, + controls: 'Управление', + rfid: { + reread: 'Повторно считать RFID', + }, + ams: { + load: 'Загрузить', + unload: 'Выгрузить', + }, + bedJog: { + title: 'Ручное перемещение', + bed: 'Стол', + step: 'Шаг (мм)', + up: 'Поднять стол', + down: 'Опустить стол', + disabledWhilePrinting: 'Недоступно во время печати', + notHomedTitle: 'Принтер не выполнил парковку по осям', + notHomedMessage: 'После последней печати принтер не выполнял Home. Сначала запустите автоматическую парковку для безопасного позиционирования (парковка печатающей головы и поиск нуля по X, Y и Z) либо продолжите перемещение — программные концевики будут отключены.', + homeZ: 'Автопарковка', + moveAnyway: 'Всё равно переместить', + homingStarted: 'Выполняется автопарковка…', + }, + permission: { + noAdd: 'У вас нет разрешения на добавление принтеров', + noEdit: 'У вас нет разрешения на изменение принтеров', + noDelete: 'У вас нет разрешения на удаление принтеров', + noControl: 'У вас нет разрешения на управление принтерами', + noFiles: 'У вас нет разрешения на доступ к файлам принтера', + noAmsRfid: 'У вас нет разрешения на повторное считывание RFID AMS', + noSmartPlugControl: 'У вас нет разрешения на управление умными розетками', + noCamera: 'У вас нет разрешения на просмотр камер', + }, + modal: { + addTitle: 'Добавить принтер', + editTitle: 'Изменить принтер', + myPrinter: 'Мой принтер', + selectModel: 'Выберите модель…', + locationGroup: 'Расположение / группа (необязательно)', + locationPlaceholder: 'например: Мастерская, Офис, Подвал', + autoArchiveLabel: 'Автоматически архивировать завершённые печати', + fromPrinterSettings: 'Из настроек принтера', + modelOptional: 'Модель (необязательно)', + saveChanges: 'Сохранить изменения', + }, + skipObjects: { + tooltip: 'Пропустить объекты', + onlyWhilePrinting: 'Пропуск объектов доступен только во время печати', + requiresMultiple: 'Для пропуска требуется не менее двух объектов', + title: 'Пропустить объекты', + matchIdsInfo: 'Сопоставьте идентификаторы с экраном принтера', + printerShowsIds: 'На экране принтера отображаются идентификаторы объектов на пластине', + skipSelected: 'Пропустить выбранные', + skipping: 'Пропуск…', + noObjectsSelected: 'Объекты не выбраны', + selectObjectsToSkip: 'Выберите объекты, которые нужно исключить из текущей печати', + skipped: 'пропущен', + objectsSkipped: 'Объекты пропущены', + activeCount: 'Активно: {{count}}', + waitForLayer: 'Пропуск объектов доступен со второго слоя (сейчас слой {{layer}})', + skip: 'Пропустить', + confirmTitle: 'Пропустить объект?', + confirmMessage: 'Пропустить объект «{{name}}»? Это действие нельзя отменить.', + }, + confirm: { + deleteTitle: 'Удалить принтер', + deleteMessage: 'Удалить принтер «{{name}}»? Все параметры подключения будут удалены.', + deleteArchivesNote: 'Вся история печати этого принтера будет удалена безвозвратно.', + keepArchivesNote: 'История печати сохранится, но больше не будет связана с этим принтером.', + stopTitle: 'Остановить печать', + stopMessage: 'Остановить текущую печать на принтере «{{name}}»? Задание будет отменено.', + stopButton: 'Остановить печать', + pauseTitle: 'Приостановить печать', + pauseMessage: 'Приостановить текущую печать на принтере «{{name}}»?', + pauseButton: 'Приостановить печать', + resumeTitle: 'Продолжить печать', + resumeMessage: 'Продолжить печать на принтере «{{name}}»?', + resumeButton: 'Продолжить печать', + powerOnTitle: 'Включить принтер', + powerOnMessage: 'Включить питание принтера «{{name}}»?', + powerOnButton: 'Включить питание', + powerOffTitle: 'Выключить принтер', + powerOffMessage: 'Выключить питание принтера «{{name}}»?', + powerOffWarning: 'ВНИМАНИЕ: принтер «{{name}}» сейчас печатает. Выключение питания прервёт печать и может повредить принтер. Продолжить?', + powerOffButton: 'Выключить питание', + haToggleTitle: 'Переключить «{{name}}»', + haToggleMessage: 'Переключить сущность Home Assistant {{entity}}? Если она сейчас включена, питание может отключиться.', + haToggleWarning: 'ВНИМАНИЕ: принтер «{{name}}» сейчас печатает. Переключение {{entity}} может отключить питание и прервать печать. Продолжить?', + haToggleButton: 'Переключить', + }, + bulk: { + select: 'Выбрать', + selectAll: 'Выбрать все', + selectByLocation: 'Выбрать по расположению', + selected: 'Выбрано: {{count}}', + actions: { + stop: 'Стоп', + pause: 'Пауза', + resume: 'Продолжить', + clearPlate: 'Освободить стол', + clearHMS: 'Очистить уведомления', + }, + confirm: { + stopTitle: 'Остановить печати: {{count}}', + stopMessage: 'Активные печати на {{count}} принтерах будут отменены. Это действие нельзя отменить.', + stopButton: 'Остановить все', + pauseTitle: 'Приостановить печати: {{count}}', + pauseMessage: 'Активные печати на {{count}} принтерах будут приостановлены.', + pauseButton: 'Приостановить все', + clearPlateTitle: 'Освободить столы: {{count}}', + clearPlateMessage: 'Столы на {{count}} принтерах будут отмечены как свободные; после этого могут запуститься задания из очереди.', + clearPlateButton: 'Освободить все', + }, + success: 'Действие «{{action}}» выполнено на {{count}} принтерах', + partial: 'Успешно: {{succeeded}}, с ошибкой: {{failed}}', + noneApplicable: 'Ни один из выбранных принтеров не находится в подходящем состоянии', + selectByState: 'Выбрать по состоянию', + }, + discovery: { + title: 'Поиск принтеров', + searching: 'Поиск…', + scanning: 'Сканирование…', + scanProgress: 'Сканирование: {{scanned}}/{{total}}', + foundPrinters: 'Найдено принтеров: {{count}}', + noPrintersFound: 'Принтеры не найдены', + noPrintersFoundSubnet: 'В указанной подсети принтеры не найдены.', + noPrintersFoundNetwork: 'Принтеры в сети не найдены.', + allConfigured: 'Все найденные принтеры уже настроены.', + alreadyAdded: 'Уже добавлен', + select: 'Выбрать', + manualEntry: 'Добавить вручную', + addFromCloud: 'Добавить из облака', + subnetToScan: 'Подсеть для сканирования', + dockerNote: 'Обнаружен Docker. Укажите подсеть принтера в формате CIDR. В docker-compose.yml требуется network_mode: host.', + scanSubnet: 'Сканировать подсеть', + discoverNetwork: 'Найти принтеры в сети', + scanningSubnet: 'Поиск принтеров Bambu в подсети…', + scanningNetwork: 'Сканирование сети…', + serialRequired: 'Требуется серийный номер', + unknown: 'Неизвестно', + failedToStart: 'Не удалось запустить поиск', + customSubnetOption: 'Другая подсеть…', + customSubnetLabel: 'Другая подсеть (CIDR)', + customSubnetNote: 'Используйте другую подсеть, если принтер находится в иной сети. Порты FTP (990) и MQTT (8883) должны быть доступны через маршрутизатор.', + }, + delete: 'Удалить этот принтер?', + unsavedChanges: 'Есть несохранённые изменения. Покинуть страницу?', + clearQueue: 'Очистить очередь печати?', + drying: { + start: 'Начать сушку', + stop: 'Остановить сушку', + temperature: 'Температура', + duration: 'Продолжительность', + hours: 'ч', + timeRemaining: 'осталось {{time}}', + active: 'Сушка', + targetSummary: '{{filament}} при {{temp}} °C', + notSupported: 'Сушка не поддерживается', + powerRequired: 'Подключите адаптер питания AMS, чтобы включить сушку', + startingDrying: 'Запуск сушки...', + stoppingDrying: 'Остановка сушки...', + rotateTray: 'Вращать катушку во время сушки', + rotateUnavailableReason: 'Недоступно: слот этого AMS сейчас подаёт филамент в печатающую головку. Катушка зафиксирована подающей трубкой и не может вращаться. Сначала выгрузите филамент.', + }, + amsBackup: { + titleOn: 'Резервный филамент AMS включён. Нажмите, чтобы отключить.', + titleOff: 'Резервный филамент AMS выключен. Нажмите, чтобы включить.', + titleUnknown: 'Состояние резервного филамента AMS недоступно для этого принтера.', + toastEnabled: 'Резервный филамент AMS включён', + toastDisabled: 'Резервный филамент AMS отключён', + modalTitle: 'Резервный филамент AMS', + modalHelp: 'Когда активный слот опустеет, принтер по очереди использует подходящие слоты с тем же профилем и цветом в указанном порядке.', + modalNoSlots: 'Филамент не загружен.', + modalNoPairs: 'Резервных пар нет: ни у двух слотов не совпадают профиль филамента и цвет.', + extruderRightShort: 'П', + extruderLeftShort: 'Л', + stateOn: 'Включено', + stateOff: 'Отключено', + stateUnknown: 'Не поддерживается этим принтером', + }, + activeJobSlot: { + title: 'Этот слот используется как филамент {{n}} в текущей печати', + ariaLabel: 'Слот {{n}} текущей печати', + }, + filaments: 'Филаменты', + openCameraOverlay: 'Открыть камеру поверх интерфейса', + openCameraWindow: 'Открыть камеру в новом окне', + firmwareUpdateAvailable: 'Доступно обновление прошивки: {{current}} → {{latest}}', + firmwareUpToDate: 'Прошивка {{version}} — актуальная версия', + firmwareUpdateButton: 'Обновить', + plateDetection: { + noPermission: 'У вас нет прав на изменение настроек принтера', + enabledClick: 'Проверка пластины включена — нажмите, чтобы отключить', + disabledClick: 'Проверка пластины отключена — нажмите, чтобы включить', + manageCalibration: 'Управление калибровкой проверки пластины', + calibrationRequired: 'Требуется калибровка', + calibrationInstructions: 'Убедитесь, что печатная пластина полностью пустая, затем нажмите «Калибровать».', + calibrationDescription: 'При калибровке сохраняется эталонное изображение пустой пластины. При последующих проверках система сравнивает снимок с эталоном и обнаруживает посторонние объекты.', + calibrationTip: 'Совет: можно сохранить до 5 калибровок для разных пластин. При проверке система автоматически выберет наиболее подходящий эталон.', + plateEmpty: 'Пластина выглядит пустой', + objectsDetected: 'На пластине обнаружены объекты', + confidence: 'Уверенность', + difference: 'Различие', + analysisPreview: 'Предпросмотр анализа:', + analysisLegend: 'Зелёная рамка — область обнаружения, красная заливка — отличия от калибровочного снимка', + savedReferences: 'Сохранённые эталоны ({{count}}/{{max}})', + deleteReference: 'Удалить эталон', + labelPlaceholder: 'Метка...', + clickToEdit: '{{label}} — нажмите для изменения', + clickToAddLabel: 'Нажмите, чтобы добавить метку', + }, + speed: { + title: 'Скорость печати', + silent: 'Тихий (50%)', + standard: 'Стандартный (100%)', + sport: 'Спортивный (124%)', + ludicrous: 'Безумный (166%)', + }, + airduct: { + title: 'Режим воздуховода', + cooling: 'Охлаждение', + heating: 'Нагрев', + }, + noSdCard: 'Нет SD-карты', + door: { + open: 'Открыта', + closed: 'Закрыта', + }, + fans: { + partCooling: 'Вентилятор обдува модели', + auxiliary: 'Дополнительный вентилятор', + chamber: 'Вентилятор камеры', + }, + clickToViewHmsErrors: 'Нажмите, чтобы посмотреть ошибки HMS', + estimatedCompletion: 'Расчётное время завершения', + plateNumber: 'Пластина {{number}}', + slotOptions: 'Параметры слота', + amsPopup: { + friendlyName: 'Имя AMS', + friendlyNamePlaceholder: 'Например, левый AMS', + serialNumber: 'Серийный номер', + firmwareVersion: 'Прошивка', + save: 'Сохранить', + clear: 'Очистить', + noEditPermission: 'У вас нет прав на переименование модулей AMS', + }, + firmwareModal: { + title: 'Обновление прошивки', + titleUpToDate: 'Сведения о прошивке', + currentVersion: 'Текущая:', + latestVersion: 'Последняя:', + releaseNotes: 'Примечания к выпуску', + checkingPrereqs: 'Проверка условий...', + sdCardReady: 'SD-карта готова. Нажмите ниже, чтобы загрузить прошивку.', + uploadedSuccess: 'Прошивка загружена на SD-карту!', + applyInstructions: 'Чтобы установить обновление на принтер:', + step1: 'На экране принтера откройте Настройки', + step2: 'Перейдите в раздел Прошивка', + step3: 'Выберите Обновить с SD-карты', + step4: 'Обновление займёт 10–20 минут', + done: 'Готово', + starting: 'Запуск...', + uploadFirmware: 'Загрузить прошивку', + uploadFailed: 'Не удалось начать загрузку: {{error}}', + uploadedToast: 'Прошивка загружена. Запустите обновление с экрана принтера.', + availableVersions: 'Доступные версии', + usable: 'Доступна', + unavailable: 'Недоступна', + installed: 'Установлена', + newerBadge: 'новее', + olderBadge: 'старее', + currentBadge: 'текущая', + }, + accessCodePlaceholder: 'Оставьте пустым, чтобы сохранить текущий', + roi: { + title: 'Область обнаружения (ROI)', + xStart: 'Начало X', + yStart: 'Начало Y', + width: 'Ширина', + height: 'Высота', + instruction: 'Настройте область обнаружения так, чтобы она охватывала печатную пластину. Зелёная рамка в предпросмотре показывает текущую область.', + }, + developerModeWarning: 'Режим LAN для разработчиков не включён на: {{names}}. Некоторые функции могут не работать.', + howToEnable: 'Как включить', + incompatibleFile: 'Файл подготовлен для {{slicedFor}}, а выбранный принтер — {{printerModel}}', + dropNotPrintable: 'Для печати подходят только файлы .gcode и .gcode.3mf', + dropToPrint: 'Перетащите файл для печати', + cannotPrint: 'Принтер занят', + }, + archives: { + title: 'Архив печати', + no3mfBanner: { + title: 'Некоторые последние задания сохранены без миниатюр', + body: 'Слайсер не оставил файл .gcode.3mf на SD-карте принтера, поэтому Bambuddy не смог получить миниатюру и метаданные слайсера. Обычно это происходит, если в слайсере отключена настройка «Сохранять отправленные файлы во внешнем хранилище» (вкладка «Устройство» в Bambu Studio / OrcaSlicer).', + docsLink: 'См. шаг 4 установки', + dismissLabel: 'Закрыть это уведомление', + }, + searchPlaceholder: 'Поиск в архиве...', + filterByPrinter: 'Фильтр по принтеру', + filterByStatus: 'Фильтр по состоянию', + sortBy: 'Сортировать по', + sortNewest: 'Сначала новые', + sortOldest: 'Сначала старые', + sortName: 'Названию', + sortDuration: 'Длительности', + sortLargest: 'Сначала большие', + sortSmallest: 'Сначала маленькие', + sortSize: 'Размеру', + noArchives: 'Архивы не найдены', + noArchivesSearch: 'По вашему запросу ничего не найдено', + originalPrintNotVisible: 'Исходная печать не отображается — попробуйте сбросить фильтры', + noArchivesYet: 'Архив пока пуст', + prints: 'печатей', + pagination: { + showing: 'Показано', + to: '–', + of: 'из', + show: 'Показывать', + page: 'Страница', + all: 'Все', + }, + loadingArchives: 'Загрузка архива...', + releaseToUpload: 'Отпустите файлы для загрузки', + showAll: 'Показать все', + showFavoritesOnly: 'Только избранное', + gridView: 'Плитка', + listView: 'Список', + calendarView: 'Календарь', + logView: 'Журнал печати', + manageTags: 'Управление тегами', + showFailedPrints: 'Показывать неудачные печати', + hideFailedPrints: 'Скрывать неудачные печати', + hideDuplicates: 'Скрывать дубликаты', + viewOriginalPrint: 'Открыть исходную печать №{{id}}', + printTime: 'Время печати', + filamentUsed: 'Израсходовано филамента', + cost: 'Стоимость', + preview: 'Предпросмотр', + deleteArchive: 'Удалить запись из архива', + deleteConfirm: 'Удалить эту запись из архива?', + favorite: 'В избранное', + unfavorite: 'Удалить из избранного', + viewDetails: 'Подробнее', + status: { + completed: 'Завершено', + failed: 'Ошибка', + stopped: 'Остановлено', + }, + toast: { + source3mfAttached: 'Исходный 3MF прикреплён: {{filename}}', + failedUploadSource3mf: 'Не удалось загрузить исходный 3MF', + source3mfRemoved: 'Исходный 3MF удалён', + failedRemoveSource3mf: 'Не удалось удалить исходный 3MF', + f3dAttached: 'F3D прикреплён: {{filename}}', + failedUploadF3d: 'Не удалось загрузить F3D', + f3dRemoved: 'F3D удалён', + failedRemoveF3d: 'Не удалось удалить F3D', + timelapseAttached: 'Таймлапс прикреплён: {{filename}}', + timelapseAlreadyAttached: 'Таймлапс уже прикреплён', + noMatchingTimelapse: 'Подходящий таймлапс не найден', + failedScanTimelapse: 'Не удалось найти таймлапс', + failedAttachTimelapse: 'Не удалось прикрепить таймлапс', + timelapseRemoved: 'Таймлапс удалён', + failedRemoveTimelapse: 'Не удалось удалить таймлапс', + timelapseUploaded: 'Таймлапс загружен: {{filename}}', + failedUploadTimelapse: 'Не удалось загрузить таймлапс', + archiveDeleted: 'Запись удалена из архива', + failedDeleteArchive: 'Не удалось удалить запись из архива', + addedToFavorites: 'Добавлено в избранное', + removedFromFavorites: 'Удалено из избранного', + projectUpdated: 'Проект обновлён', + failedUpdateProject: 'Не удалось обновить проект', + linkCopied: 'Ссылка скопирована', + failedCopyLink: 'Не удалось скопировать ссылку', + photoDeleted: 'Фотография удалена', + failedDeletePhoto: 'Не удалось удалить фотографию', + failedDeleteArchives: 'Не удалось удалить записи из архива', + failedUpdateFavorites: 'Не удалось обновить избранное', + exportDownloaded: 'Экспортированный файл скачан', + exportFailed: 'Ошибка экспорта', + }, + menu: { + print: 'Печать', + openInBambuStudio: 'Открыть в слайсере', + slice: 'Нарезать', + externalLink: 'Внешняя ссылка', + viewOnMakerWorld: 'Открыть на MakerWorld', + preview3d: '3D-просмотр', + viewTimelapse: 'Посмотреть таймлапс', + scanForTimelapse: 'Найти таймлапс', + uploadTimelapse: 'Загрузить таймлапс', + removeTimelapse: 'Удалить таймлапс', + downloadSource3mf: 'Скачать исходный 3MF', + uploadSource3mf: 'Загрузить исходный 3MF', + replaceSource3mf: 'Заменить исходный 3MF', + removeSource3mf: 'Удалить исходный 3MF', + uploadF3d: 'Загрузить F3D', + replaceF3d: 'Заменить F3D', + downloadF3d: 'Скачать F3D', + removeF3d: 'Удалить F3D', + download: 'Скачать', + copyDownloadLink: 'Скопировать ссылку для скачивания', + qrCode: 'QR-код', + viewPhotos: 'Посмотреть фотографии', + viewPhotosCount: 'Фотографии ({{count}})', + projectPage: 'Страница проекта', + addToFavorites: 'Добавить в избранное', + removeFromFavorites: 'Удалить из избранного', + edit: 'Изменить', + printLog: 'Журнал печати', + goToProject: 'Открыть проект: {{name}}', + addToProject: 'Добавить в проект', + removeFromProject: 'Удалить из проекта', + loading: 'Загрузка...', + noProjectsAvailable: 'Нет доступных проектов', + searchProjects: 'Поиск проектов…', + select: 'Выбрать', + deselect: 'Снять выделение', + delete: 'Удалить', + }, + permission: { + noReprint: 'У вас нет разрешения на повторную печать этой записи', + noAddToQueue: 'У вас нет разрешения на добавление в очередь', + noUpdateArchives: 'У вас нет разрешения на изменение архива', + noUploadFiles: 'У вас нет разрешения на загрузку файлов', + noDownload: 'У вас нет разрешения на скачивание файлов из архива', + noCopyLink: 'У вас нет разрешения на копирование ссылок для скачивания', + noDelete: 'У вас нет разрешения на удаление этой записи', + noEdit: 'У вас нет разрешения на изменение этой записи', + noCreate: 'У вас нет разрешения на создание записей в архиве', + }, + platePicker: { + title: 'Выберите пластину для предпросмотра', + hint: 'В этой записи несколько пластин. Выберите пластину, которую нужно открыть в просмотрщике G-code.', + plateLabel: 'Пластина {{index}}', + objectCount: '{{count}} объект', + objectCount_plural: '{{count}} объектов', + noGcode: 'В этой записи нет нарезанного G-code для предпросмотра. Сначала откройте файл в Bambu Studio и выполните нарезку.', + }, + card: { + previousPlate: 'Предыдущая пластина', + nextPlate: 'Следующая пластина', + plateNumber: 'Пластина {{index}}', + moreOptions: 'Щёлкните правой кнопкой для дополнительных действий', + addToFavorites: 'Добавить в избранное', + removeFromFavorites: 'Удалить из избранного', + cancelled: 'отменено', + failed: 'ошибка', + duplicate: 'дубликат', + duplicateTitle: 'Эта модель уже печаталась', + openSource3mf: 'Открыть исходный 3MF в Bambu Studio (щёлкните правой кнопкой для дополнительных действий)', + downloadF3d: 'Скачать файл проекта Fusion 360', + viewTimelapse: 'Посмотреть таймлапс', + viewPhoto: 'Посмотреть фотографию', + viewPhotos: 'Посмотреть фотографии: {{count}}', + openFolder: 'Открыть папку: {{name}}', + slicedFile: 'Нарезанный файл — готов к печати', + sourceFile: 'Только исходный файл — сопоставление AMS недоступно', + gcode: 'G-CODE', + source: 'ИСХОДНИК', + project: 'Проект: {{name}}', + runsBadge: 'Печатей: {{count}}', + runsBadgeTitle: 'Всего печатей: {{count}}, успешных: {{successful}}, неудачных: {{failed}}. Нажмите, чтобы открыть полный журнал.', + estimated: 'Расчётное время: {{time}}', + actual: 'Фактическое время: {{time}}', + accuracy: 'Точность оценки: {{percent}}%', + filament: '{{weight}} г', + layer: '{{count}} слой', + layers: '{{count}} слоёв', + object: '{{count}} объект', + objects: '{{count}} объектов', + slicedFor: 'Нарезано для {{model}}', + uploadedBy: 'Загрузил', + noPermissionReprint: 'У вас нет разрешения на повторную печать', + noFileForReprint: 'Файл 3MF недоступен: при сохранении задания не удалось скачать его с принтера', + noPermissionEdit: 'У вас нет разрешения на изменение архива', + noPermissionDelete: 'У вас нет разрешения на удаление записей из архива', + openInBambuStudio: 'Открыть в слайсере', + openInBambuStudioToSlice: 'Открыть в слайсере для нарезки', + slice: 'Нарезать', + externalLink: 'Внешняя ссылка', + makerWorld: 'MakerWorld: {{designer}}', + viewProject: 'Открыть проект', + noExternalLink: 'Внешняя ссылка не указана', + preview3d: '3D-просмотр', + download: 'Скачать', + edit: 'Изменить', + delete: 'Удалить', + }, + runLog: { + title: 'Журнал печати', + modalTitle: 'Журнал печати — {{name}}', + modalTitleFallback: 'эта запись', + empty: 'Для этой записи пока нет событий печати.', + col: { + date: 'Дата', + status: 'Состояние', + duration: 'Длительность', + filament: 'Филамент', + cost: 'Стоимость', + }, + status: { + completed: 'Завершено', + failed: 'Ошибка', + cancelled: 'Отменено', + stopped: 'Остановлено', + skipped: 'Пропущено', + printing: 'Печать', + }, + }, + modal: { + deleteArchive: 'Удаление записи из архива', + deleteConfirm: 'Удалить «{{name}}»? Это действие нельзя отменить.', + deleteButton: 'Удалить', + deletePurgeStats: 'Также исключить эту печать из краткой статистики: филамент, время, стоимость и энергия', + deleteQueueItemsWarning: 'Также будут удалены связанные элементы очереди: {{count}}.', + deleteBlockedByPrinting: 'Удаление невозможно: сейчас печатаются связанные элементы очереди ({{count}}). Сначала остановите печать.', + removeSource3mf: 'Удаление исходного 3MF', + removeSource3mfConfirm: 'Удалить исходный файл 3MF из «{{name}}»? Исходный проект слайсера будет удалён.', + removeButton: 'Удалить', + removeF3d: 'Удаление F3D', + removeF3dConfirm: 'Удалить файл проекта Fusion 360 из «{{name}}»?', + removeTimelapse: 'Удаление таймлапса', + removeTimelapseConfirm: 'Удалить видео таймлапса из «{{name}}»?', + timelapse: '{{name}} — таймлапс', + selectTimelapse: 'Выбор таймлапса', + selectTimelapseDesc: 'Автоматически найти совпадение не удалось. Выберите таймлапс для этой печати:', + deleteArchives: 'Удаление записей из архива', + deleteArchivesConfirm: 'Удалить записи из архива ({{count}})? Это действие нельзя отменить.', + deleteCount: 'Удалить: {{count}}', + }, + page: { + title: 'Архив', + printsCount: 'Показано {{filtered}} из {{total}} печатей', + dropFilesHere: 'Перетащите сюда файлы .3mf', + releaseToUpload: 'Отпустите файлы для загрузки', + only3mfSupported: 'Поддерживаются только файлы .3mf', + close: 'Закрыть', + selected: 'Выбрано: {{count}}', + selectAll: 'Выбрать все', + tags: 'Теги', + project: 'Проект', + favorite: 'Избранное', + delete: 'Удалить', + toggledFavorites: 'Избранное изменено для записей: {{count}}', + failedUpdateFavorites: 'Не удалось обновить избранное', + archivesDeleted: 'Удалено записей: {{count}}', + failedDeleteArchives: 'Не удалось удалить записи из архива', + photoDeleted: 'Фотография удалена', + failedDeletePhoto: 'Не удалось удалить фотографию', + }, + list: { + name: 'Название', + printer: 'Принтер', + date: 'Дата', + size: 'Размер', + actions: 'Действия', + hasTimelapse: 'Есть таймлапс', + }, + log: { + date: 'Дата', + printName: 'Название печати', + printer: 'Принтер', + user: 'Пользователь', + status: 'Состояние', + duration: 'Длительность', + filament: 'Филамент', + allPrinters: 'Все принтеры', + allUsers: 'Все пользователи', + allStatuses: 'Все состояния', + cancelled: 'Отменено', + skipped: 'Пропущено', + dateFrom: 'С', + dateTo: 'По', + noEntries: 'Записи журнала не найдены', + showing: 'Показано {{count}} из {{total}} записей', + rowsPerPage: 'Строк', + page: 'Страница', + prev: 'Назад', + next: 'Далее', + clearLog: 'Очистить журнал', + clearLogTitle: 'Очистка журнала печати', + clearLogConfirm: 'Все записи журнала печати будут удалены без возможности восстановления. Архив и очередь не изменятся. Продолжить?', + clearLogButton: 'Очистить всё', + cleared: 'Удалено записей журнала: {{count}}', + clearFailed: 'Не удалось очистить журнал печати', + deleteEntryTitle: 'Удаление записи журнала', + deleteEntryConfirm: 'Запись будет удалена из журнала, а её вклад в расход филамента, время и стоимость исчезнет из краткой статистики. Связанная запись архива, если она существует, не изменится. Это действие нельзя отменить.', + entryDeleted: 'Запись журнала удалена', + entryDeleteFailed: 'Не удалось удалить запись журнала', + editEntryTitle: 'Изменение записи журнала', + editEntryDescription: 'Укажите результат этой печати. Виджет анализа отказов группирует данные по этим значениям, поэтому изменения сразу отразятся в статистике.', + entryUpdated: 'Запись журнала обновлена', + entryUpdateFailed: 'Не удалось обновить запись журнала', + statuses: { + completed: 'Завершено', + failed: 'Ошибка', + stopped: 'Остановлено', + cancelled: 'Отменено', + skipped: 'Пропущено', + }, + }, + }, + dispatchToast: { + untitled: 'Задание печати', + startingPrints: 'Запуск печати', + progressSummary: 'Завершено: {{complete}}/{{total}} • Обрабатывается: {{processing}}', + expandDetails: 'Показать подробности отправки', + collapseDetails: 'Скрыть подробности отправки', + awaitingPrinter: 'Ожидание принтера…', + status: { + processing: 'Обработка', + completed: 'Завершено', + failed: 'Ошибка', + }, + failed: { + generic: 'Не удалось отправить задание', + upload_failed: 'Не удалось загрузить файл на принтер', + start_command_failed: 'Принтер отклонил команду запуска', + }, + dismiss: 'Закрыть', + }, + pipelineRuns: { + title: 'Запуски конвейеров', + loading: 'Загрузка…', + empty: 'Конвейеры ещё не запускались.', + filter: { + pipeline: 'Конвейер', + status: 'Состояние', + target: 'Назначение', + all: 'Все', + allPipelines: 'Все конвейеры', + allStatus: 'Все состояния', + allTargets: 'Все назначения', + clear: 'Сбросить фильтры', + noMatches: 'Нет запусков, соответствующих выбранным фильтрам.', + }, + totalCount_one: '{{n}} запуск', + totalCount_other: '{{n}} запусков', + copies: 'Копий: {{n}}', + failedCount: 'Ошибок: {{n}}', + copyN: 'Копия {{n}}', + retryFailed: 'Повторить неудачные', + retryOf: 'повтор запуска №{{n}}', + pagination: '{{start}}–{{end}} из {{total}}', + cancelledByUser: 'Отменено пользователем', + toast: { + cancelled: 'Запуск отменён', + cancelFailed: 'Не удалось отменить запуск', + retryStarted: 'Повторный запуск начат', + retryFailed: 'Повторный запуск не удался', + cleared: 'Удалено запусков: {{n}}', + clearFailed: 'Не удалось очистить журнал', + }, + clearLog: 'Очистить журнал', + clearConfirmTitle: 'Очистить журнал?', + clearConfirmBody: 'Удалить все завершённые, неудачные, отменённые и частично неудачные запуски конвейеров? Выполняющиеся запуски сохранятся. Это действие нельзя отменить.', + clearConfirmAction: 'Очистить', + jobStatus: { + pending: 'ожидание', + awaiting_printer: 'ожидание принтера', + queued: 'в очереди', + printing: 'печать', + completed: 'завершено', + failed: 'ошибка', + cancelled: 'отменено', + }, + }, + queue: { + title: 'Очередь печати', + subtitle: 'Планирование и управление заданиями печати', + filamentShort: { + rowBadge: 'Для назначенной катушки недостаточно филамента', + rowTooltip: 'Планировщик отметил это задание. Нажмите «Запустить», чтобы увидеть нехватку по каждому слоту и решить, печатать ли всё равно.', + confirmTitle: 'Недостаточно филамента', + confirmIntro: 'Назначенной катушки недостаточно как минимум для одного слота. Всё равно запустить печать?', + lineItem: 'Слот {{slot}}: требуется {{required}} г, осталось {{remaining}} г', + unknown: 'неизвестно', + printAnyway: 'Всё равно печатать', + }, + editQueueItem: 'Изменить задание в очереди', + selectAllPlates: 'Выбрать все пластины ({{count}})', + deselectAll: 'Снять выделение', + printQueued: 'Задание добавлено в очередь', + printQueuedWillStartWhenIdle: 'Запустится, когда принтер освободится', + itemsQueued: 'Добавлено в очередь: {{count}}', + sending: 'Отправка...', + sendingProgress: 'Отправка {{current}} из {{total}}...', + adding: 'Добавление...', + addingProgress: 'Добавление {{current}} из {{total}}...', + savingProgress: 'Сохранение {{current}} из {{total}}...', + clearQueue: 'Очистить очередь', + clearHistory: 'Очистить историю', + emptyQueue: 'Очередь пуста', + position: 'Позиция', + scheduledTime: 'Запланированное время', + moveUp: 'Переместить вверх', + moveDown: 'Переместить вниз', + startNow: 'Запустить сейчас', + printingInProgress: 'Идёт печать...', + viewArchive: 'Открыть архив', + viewInFileManager: 'Открыть в файловом менеджере', + itemCount: '{{count}} задание', + itemCount_plural: '{{count}} заданий', + dragToReorder: 'Перетащите для изменения порядка (только задания «как можно скорее»)', + reorderHint: 'Позиция влияет только на задания «как можно скорее». Запланированные задания запускаются в указанное время.', + sjf: { + label: 'SJF', + tooltip: 'Shortest Job First — планировщик отдаёт приоритет более коротким заданиям', + }, + addedBy: 'Добавил: {{name}}', + nextInQueue: 'Следующее в очереди', + clearPlateSuccess: 'Пластина очищена — можно запускать следующую печать', + plateNumber: 'Пластина {{index}}', + quantity: 'Количество', + quantityHint: 'Будет создано заданий: {{count}}', + activeBatches: 'Активные партии', + batchProgress: 'Выполнено {{completed}} из {{total}}', + cancelBatch: 'Отменить оставшиеся', + batchCancelled: 'Оставшиеся задания партии отменены', + cancelBatchConfirmTitle: 'Отменить партию', + cancelBatchConfirmMessage: 'Отменить все оставшиеся задания этой партии?', + batch: { + defaultName: 'Партия', + label: '{{count}} задание', + label_plural: '{{count}} заданий', + pendingCount: 'Ожидает: {{count}}', + pendingCount_plural: 'Ожидают: {{count}}', + expand: 'Развернуть партию', + collapse: 'Свернуть партию', + groupAsBatch: 'Объединить в партию…', + groupAsBatchDescription: 'Объединить выбранные задания ({{count}}) в одну сворачиваемую партию.', + nameLabel: 'Название партии', + namePlaceholder: 'Например: подарки к пятнице', + create: 'Создать партию', + ungroup: 'Разгруппировать', + ungroupConfirmTitle: 'Разгруппировать партию?', + ungroupConfirmMessage: 'Задания останутся в очереди, но больше не будут объединены в одну группу.', + dragGroup: 'Перетащить группу', + }, + tabs: { + queue: 'Очередь', + history: 'История', + timeline: 'Временная шкала', + pipelines: 'Конвейеры', + }, + layout: { + flatList: 'Список', + byPrinter: 'По принтерам', + groupByPrinter: 'Группировать по принтерам', + }, + history: { + emptyTitle: 'История пока пуста', + emptyDescription: 'Здесь появятся завершённые, отменённые и неудачные задания.', + }, + dragGhost: { + multiCount: '{{count}} заданий', + batch: '{{name}} ({{count}} копия)', + batch_plural: '{{name}} ({{count}} копий)', + }, + sections: { + currentlyPrinting: 'Сейчас печатается', + queued: 'В очереди', + history: 'История', + }, + status: { + pending: 'Ожидает', + waiting: 'Ожидание', + printing: 'Печать', + paused: 'Приостановлено', + completed: 'Завершено', + failed: 'Ошибка', + skipped: 'Пропущено', + cancelled: 'Отменено', + }, + summary: { + printing: 'Печатается', + queued: 'В очереди', + totalTime: 'Общее время очереди', + totalWeight: 'Общий вес очереди', + history: 'История', + }, + filter: { + allPrinters: 'Все принтеры', + unassigned: 'Не назначено', + allStatus: 'Все состояния', + allLocations: 'Все расположения', + any: 'Любое', + }, + sort: { + byPosition: 'По позиции', + byName: 'По названию', + byPrinter: 'По принтеру', + bySchedule: 'По времени запуска', + byDate: 'По дате', + ascendingOldest: 'По возрастанию (сначала старые)', + descendingNewest: 'По убыванию (сначала новые)', + }, + badges: { + staged: 'Подготовлено', + requiresPrevious: 'Требуется успешное предыдущее задание', + autoPowerOff: 'Автоотключение питания', + gcodeInjection: 'G-code', + }, + empty: { + title: 'Нет запланированных заданий', + description: 'Запланируйте печать на странице архива через пункт «Запланировать» в контекстном меню либо перетащите сюда файлы.', + }, + time: { + asap: 'Как можно скорее', + overdue: 'Просрочено', + now: 'Сейчас', + lessThanMinute: 'Меньше чем через минуту', + inMinutes: 'Через {{count}} мин', + inHours: 'Через {{count}} ч', + }, + actions: { + startPrint: 'Запустить печать', + stopPrint: 'Остановить печать', + requeue: 'Вернуть в очередь', + }, + bulkEdit: { + title: 'Изменить {{count}} задание', + title_plural: 'Изменить задания: {{count}}', + description: 'К выбранным заданиям будут применены только изменённые параметры.', + printer: 'Принтер', + noChange: '— Без изменений —', + queueOptions: 'Параметры очереди', + staged: 'Подготовлено (ручной запуск)', + autoPowerOff: 'Отключить питание после печати', + requirePrevious: 'Требовать успешного завершения предыдущего задания', + printOptions: 'Параметры печати', + bedLevelling: 'Калибровка стола', + flowCalibration: 'Калибровка потока', + vibrationCalibration: 'Калибровка вибраций', + layerInspection: 'Проверка первого слоя', + timelapse: 'Таймлапс', + useAms: 'Использовать AMS', + nozzleOffsetCali: 'Калибровка смещения сопел', + applyChanges: 'Применить изменения', + selectAll: 'Выбрать все', + deselectAll: 'Снять выделение', + selected: 'Выбрано: {{count}}', + editSelected: 'Изменить выбранные', + cancelSelected: 'Отменить выбранные', + }, + confirm: { + cancelTitle: 'Отменить запланированную печать', + cancelMessage: 'Отменить задание «{{name}}»?', + stopTitle: 'Остановить печать', + stopMessage: 'Остановить текущую печать «{{name}}»? Задание на принтере будет отменено.', + removeTitle: 'Удалить из истории', + removeMessage: 'Удалить «{{name}}» из истории очереди?', + clearHistoryTitle: 'Очистить историю', + clearHistoryMessage: 'Удалить все записи из истории ({{count}})?', + cancelButton: 'Отменить печать', + stopButton: 'Остановить печать', + thisPrint: 'эту печать', + thisItem: 'это задание', + }, + toast: { + cancelled: 'Задание отменено', + cancelFailed: 'Не удалось отменить задание', + removed: 'Задание удалено', + removeFailed: 'Не удалось удалить задание', + stopped: 'Печать остановлена', + stopFailed: 'Не удалось остановить печать', + released: 'Задание передано в очередь', + startFailed: 'Не удалось запустить печать', + reorderFailed: 'Не удалось изменить порядок очереди', + historyCleared: 'Удалено записей истории: {{count}}', + clearHistoryFailed: 'Не удалось очистить историю', + updateFailed: 'Не удалось обновить задания', + bulkCancelled: 'Отменено заданий: {{count}}', + bulkCancelFailed: 'Не удалось отменить задания', + batchCreated: 'Партия «{{name}}» создана', + batchCreateFailed: 'Не удалось создать партию', + batchUngrouped: 'Разгруппировано заданий: {{count}}', + batchUngroupFailed: 'Не удалось разгруппировать партию', + resumedAfterFailure: 'Очередь возобновлена — восстановлено заданий: {{restored}}', + resumeAfterFailureFailed: 'Не удалось возобновить очередь', + }, + resumeAfterFailure: { + banner: 'Очередь принтера {{printer}} заблокирована из-за ошибки предыдущей печати — пропущено заданий: {{count}}', + bannerHint: 'Устраните проблему с принтером, затем возобновите очередь, чтобы вернуть пропущенные задания и снять блокировку.', + button: 'Возобновить после ошибки', + confirmTitle: 'Возобновить очередь после ошибки?', + confirmMessage: 'Вернуть пропущенные задания ({{count}}) для принтера {{printer}} в состояние ожидания и снять блокировку. Перед продолжением убедитесь, что принтер готов.', + }, + timeline: { + listView: 'Список', + timelineView: 'Временная шкала', + unassigned: 'Не назначено', + noData: 'На этот день печать не запланирована', + nothingCommitted: 'В этом интервале нет заданий с фиксированным временем. Подготовленные и ожидающие задания, а также задания «как можно скорее» на свободных принтерах не показываются — задайте время запуска или выпустите подготовленное задание в очередь.', + allDoneBy: 'Расчётное завершение всех заданий: {{time}}', + staged: 'Подготовлено', + filterAll: 'Показать все', + filterPrinting: 'Печатается', + filterQueued: 'В очереди', + time: { + anyMoment: 'в любой момент', + minutesLeft: 'осталось {{minutes}} мин', + hoursLeft: 'осталось {{hours}} ч', + hoursMinutesLeft: 'осталось {{hours}} ч {{minutes}} мин', + }, + day: { + previous: 'Предыдущий день', + next: 'Следующий день', + today: 'Сегодня', + }, + window: { + back12h: 'Назад на 12 часов', + forward12h: 'Вперёд на 12 часов', + now: 'Сейчас', + }, + printerColumnHeader: 'Принтер', + }, + permissions: { + noStopPrint: 'У вас нет разрешения останавливать печать', + noStartPrint: 'У вас нет разрешения запускать печать', + noEdit: 'У вас нет разрешения изменять это задание', + noCancel: 'У вас нет разрешения отменять это задание', + noRequeue: 'У вас нет разрешения возвращать задания в очередь', + noRemove: 'У вас нет разрешения удалять это задание', + noClearHistory: 'У вас нет разрешения очищать историю', + noEditItems: 'У вас нет разрешения изменять задания очереди', + noCancelItems: 'У вас нет разрешения отменять задания очереди', + }, + }, + stats: { + title: 'Статистика', + subtitle: 'Перетаскивайте виджеты для изменения порядка. Нажмите значок глаза, чтобы скрыть виджет.', + overview: 'Обзор', + totalPrints: 'Всего печатей', + successRate: 'Успешность', + totalPrintTime: 'Общее время печати', + printTime: 'Время печати', + totalFilament: 'Всего использовано филамента', + filamentUsed: 'Использовано филамента', + filamentCost: 'Стоимость филамента', + totalCost: 'Общая стоимость', + energyUsed: 'Потреблено энергии', + energyCost: 'Стоимость энергии', + energyWarmingUpTooltip: 'Учёт энергии ещё накапливает почасовые снимки. Итоги за выбранный период станут точными, когда появится хотя бы один снимок до начала этого периода. Первые значения могут быть занижены.', + averagePrintTime: 'Среднее время печати', + printsPerDay: 'Печатей в день', + byPrinter: 'По принтерам', + printsByPrinter: 'Печати по принтерам', + byMaterial: 'По материалам', + byMonth: 'По месяцам', + last7Days: 'Последние 7 дней', + last30Days: 'Последние 30 дней', + last90Days: 'Последние 90 дней', + allTime: 'За всё время', + quickStats: 'Краткая статистика', + printActivity: 'Активность печати', + filamentTypes: 'Типы филамента', + filamentTrends: 'Расход филамента', + failureAnalysis: 'Анализ неудач', + timeAccuracy: 'Точность оценки времени', + successful: 'Успешно:', + failed: 'Неудачно:', + cancelled: 'Отменено:', + perfectEstimate: '100% — точное совпадение с оценкой', + noTimeAccuracyData: 'Данных о точности оценки времени пока нет', + noFilamentData: 'Нет данных о филаменте', + noPrinterData: 'Нет данных о принтерах', + noPrintData: 'Нет данных о печати', + noPrintDataLast30Days: 'За последние 30 дней данных о печати нет', + failureReasons: 'Причины неудач', + topFailureReasons: 'Основные причины неудач', + failedPrintsCount: 'Неудачных печатей: {{failed}} из {{total}}', + lastWeekRate: 'За прошлую неделю: {{rate}}%', + resetLayout: 'Сбросить расположение', + recalculateCosts: 'Пересчитать стоимость', + recalculateCostsHint: 'Пересчитать стоимость всех архивных заданий по текущим ценам филамента', + exportStats: 'Экспорт статистики', + exportAsCsv: 'Экспорт в CSV', + exportAsExcel: 'Экспорт в Excel', + hiddenCount: 'Скрыто: {{count}}', + exportDownloaded: 'Файл экспорта скачан', + exportFailed: 'Не удалось экспортировать данные', + layoutReset: 'Расположение сброшено', + recalculatedCosts: 'Пересчитана стоимость архивов: {{count}}', + recalculateFailed: 'Не удалось пересчитать стоимость', + loadingStats: 'Загрузка статистики...', + noPermissionResetLayout: 'У вас нет разрешения сбрасывать расположение', + noPermissionRecalculate: 'У вас нет разрешения пересчитывать стоимость', + noPrintDataInRange: 'В выбранном периоде нет данных о печати', + periodFilament: 'Филамент за период', + periodCost: 'Стоимость за период', + avgPerPrint: 'В среднем на печать', + usageOverTime: 'Расход по времени', + filamentByWeight: 'По весу', + printDuration: 'Продолжительность печати', + printerUtilization: 'Загрузка принтеров', + filamentSuccess: 'Успешность по материалам', + printHabits: 'Характер печати', + printTimeOfDay: 'Время суток', + colorDistribution: 'Распределение по цветам', + noColorData: 'Нет данных о цветах', + records: 'Рекорды', + longestPrint: 'Самая долгая печать', + heaviestPrint: 'Самая тяжёлая печать', + mostExpensivePrint: 'Самая дорогая печать', + busiestDay: 'Самый загруженный день', + successStreak: 'Серия успешных печатей', + streakPrint: 'успешная печать подряд', + streakPrints: '{{count}} успешных печатей подряд', + printerStats: 'Статистика принтеров', + hours: 'часов', + avgPrints: 'В среднем печатей', + noArchiveData: 'Нет данных о печати', + filamentByTime: 'По времени', + avgWeight: 'Средний вес', + avgTime: 'Среднее время', + filamentByPrints: 'По количеству печатей', + timeframe: { + today: 'Сегодня', + 'this-week': 'Эта неделя', + 'this-month': 'Этот месяц', + 'last-7': 'Последние 7 дней', + 'last-30': 'Последние 30 дней', + 'last-90': 'Последние 90 дней', + 'this-year': 'Этот год', + 'all-time': 'За всё время', + custom: 'Произвольный период', + from: 'С', + to: 'По', + }, + allUsers: 'Все пользователи', + noUser: 'Без пользователя (система)', + filterByUser: 'Фильтр по пользователю', + }, + maintenance: { + title: 'Обслуживание', + overview: 'Обзор', + allOk: 'Всё обслуживание выполнено вовремя', + dueCount: 'Требуется выполнить: {{count}}', + dueCount_plural: 'Требуется выполнить: {{count}}', + warningCount: 'Предупреждений: {{count}}', + warningCount_plural: 'Предупреждений: {{count}}', + totalPrintTime: 'Общее время печати', + nextMaintenance: 'Следующее обслуживание', + nothingDue: 'Пока ничего не требуется', + tasks: 'Задачи', + lastPerformed: 'Последнее выполнение', + interval: 'Интервал', + hoursRemaining: 'Осталось {{hours}} ч', + hoursOverdue: 'Просрочено на {{hours}} ч', + markDone: 'Отметить выполненным', + performMaintenance: 'Выполнить обслуживание', + history: 'История', + noHistory: 'История обслуживания пуста', + editPrintHours: 'Изменить часы печати', + currentHours: 'Текущие часы', + statusTab: 'Состояние', + settingsTab: 'Настройки', + overdueCount: 'Просрочено: {{count}}', + dueSoonCount: 'Скоро потребуется: {{count}}', + dueSoon: 'Скоро потребуется', + allGood: 'Всё в порядке', + overdueBy: 'Просрочено на {{duration}}', + dueIn: 'Через {{duration}}', + timeLeft: 'Осталось {{duration}}', + day: '1 день', + days: '{{count}} дней', + week: '1 неделя', + weeks: '{{count}} недель', + month: '1 месяц', + months: '{{count}} месяцев', + year: '1 год', + maintenanceTypes: 'Виды обслуживания', + maintenanceTypesDescription: 'Системные и пользовательские задачи обслуживания', + addCustomType: 'Добавить пользовательскую задачу', + restoreDefaults: 'Восстановить стандартные задачи', + intervalType: 'Тип интервала', + intervalValue: 'Интервал ({{type}})', + icon: 'Значок', + documentationLink: 'Ссылка на документацию (необязательно)', + assignToPrinters: 'Назначить принтерам', + selectAtLeastOnePrinter: 'Выберите хотя бы один принтер', + addType: 'Добавить вид', + custom: 'Пользовательский', + printHours: 'Часы печати', + calendarDays: 'Календарные дни', + exampleName: 'Например: заменить HEPA-фильтр', + viewDocumentation: 'Открыть документацию', + timeBasedInterval: 'Интервал по времени', + intervalOverrides: 'Переопределение интервалов', + intervalOverridesDescription: 'Настройка отдельных интервалов для конкретных принтеров', + assignedToPrinters: 'Назначено принтерам:', + noPrintersAssigned: 'Не назначено ни одному принтеру', + addPrinterShort: 'Добавить:', + printersAssignedClick: 'Назначено принтерам: {{count}} — нажмите для управления', + removeFromPrinter: 'Убрать с этого принтера', + types: { + lubricateCarbonRods: 'Смазать карбоновые валы', + lubricateRails: 'Смазать линейные направляющие', + cleanNozzle: 'Очистить сопло/хотэнд', + checkBelts: 'Проверить натяжение ремней', + cleanBuildPlate: 'Очистить печатную пластину', + checkExtruder: 'Проверить шестерни экструдера', + checkCooling: 'Проверить вентиляторы охлаждения', + generalInspection: 'Общий осмотр', + cleanCarbonRods: 'Очистить карбоновые валы', + lubricateSteelRods: 'Смазать стальные валы', + cleanSteelRods: 'Очистить стальные валы', + cleanLinearRails: 'Очистить линейные направляющие', + checkPtfeTube: 'Проверить PTFE-трубку', + replaceHepaFilter: 'Заменить HEPA-фильтр', + replaceCarbonFilter: 'Заменить угольный фильтр', + lubricateLeftNozzleRail: 'Смазать направляющую левого сопла', + }, + maintenanceComplete: 'Обслуживание отмечено выполненным', + typeUpdated: 'Вид обслуживания обновлён', + typeDeleted: 'Вид обслуживания удалён', + defaultsRestored: 'Восстановлено стандартных задач: {{count}}', + printHoursUpdated: 'Часы печати обновлены', + printerAssigned: 'Принтер назначен', + printerRemoved: 'Принтер удалён из назначения', + deleteTypeConfirm: 'Удалить «{{name}}»?', + deleteSystemTypeTitle: 'Удалить стандартную задачу обслуживания?', + deleteSystemTypeMessage: 'Удалить стандартную задачу обслуживания «{{name}}»?', + noPermissionUpdate: 'У вас нет разрешения обновлять задачи обслуживания', + noPermissionPerform: 'У вас нет разрешения отмечать обслуживание выполненным', + noPermissionEditTypes: 'У вас нет разрешения изменять виды обслуживания', + noPermissionDeleteTypes: 'У вас нет разрешения удалять виды обслуживания', + noPermissionEditHours: 'У вас нет разрешения изменять часы печати', + noPermissionRemovePrinter: 'У вас нет разрешения удалять назначения принтеров', + noPermissionAssignPrinter: 'У вас нет разрешения назначать принтеры', + noPermissionEditIntervals: 'У вас нет разрешения изменять интервалы', + configureSettings: 'Настроить виды обслуживания и интервалы', + }, + settings: { + title: 'Настройки', + general: 'Общие', + tabs: { + general: 'Общие', + smartPlugs: 'Умные розетки', + notifications: 'Уведомления', + queue: 'Рабочий процесс', + queueDispatch: 'Очередь и отправка', + queuePipelines: 'Конвейеры', + filament: 'Филамент', + network: 'Сеть', + apiKeys: 'Ключи API', + virtualPrinter: 'Виртуальный принтер', + spoolbuddy: 'SpoolBuddy', + failureDetection: 'Обнаружение сбоев', + users: 'Аутентификация', + backup: 'Резервное копирование', + emailAuth: 'Аутентификация по email', + ldap: 'LDAP', + twoFa: 'Двухфакторная аутентификация', + oidc: 'SSO / OIDC', + security: 'Безопасность', + }, + spoolbuddy: { + infoTitle: 'Устройства SpoolBuddy', + infoBody: 'Киоски SpoolBuddy регистрируются автоматически по сигналам активности. Удалите регистрацию устройства, если оно больше не используется или после сбоя демона остался устаревший дубликат.', + duplicatesTitle: 'Зарегистрировано устройств: {{count}}', + duplicatesBody: 'Интерфейс киоска использует только первое зарегистрированное устройство. Если один из экземпляров — устаревший дубликат после сбоя, удалите его регистрацию: работающее устройство зарегистрируется снова при следующем сигнале активности.', + empty: 'Устройства SpoolBuddy пока не зарегистрированы.', + online: 'В сети', + offline: 'Не в сети', + unregister: 'Удалить регистрацию', + unregisterSuccess: 'Регистрация устройства удалена', + unregisterError: 'Не удалось удалить регистрацию устройства', + confirmTitle: 'Удалить регистрацию устройства SpoolBuddy?', + confirmBody: 'Устройство «{{hostname}}» ({{deviceId}}) будет удалено из базы данных. Если оно работает, то зарегистрируется снова при следующем сигнале активности.', + ipAddress: 'IP-адрес', + firmware: 'Прошивка', + lastSeen: 'Последняя активность', + daemonUptime: 'Время работы демона', + systemUptime: 'Время работы системы', + never: 'никогда', + nfc: 'NFC', + scale: 'Весы', + cpuTemp: 'Температура ЦП', + cpuLoad: 'Загрузка ЦП', + memory: 'Память', + disk: 'Диск', + update: 'Обновить', + updateConfirmTitle: 'Обновить демон SpoolBuddy?', + updateConfirmBody: 'Запустить обновление ПО на «{{hostname}}»? После установки обновления демон будет перезапущен.', + restartBrowser: 'Перезапустить браузер', + restartBrowserConfirmTitle: 'Перезапустить браузер киоска?', + restartBrowserConfirmBody: 'Перезапустить браузер киоска на «{{hostname}}»? Экран ненадолго погаснет.', + restartDaemon: 'Перезапустить демон', + restartDaemonConfirmTitle: 'Перезапустить демон SpoolBuddy?', + restartDaemonConfirmBody: 'Перезапустить демон SpoolBuddy на «{{hostname}}»? Устройство на несколько секунд пропадёт из сети.', + reboot: 'Перезагрузить', + rebootConfirmTitle: 'Перезагрузить устройство?', + rebootConfirmBody: 'Перезагрузить «{{hostname}}»? Устройство будет недоступно около минуты.', + shutdown: 'Выключить', + shutdownConfirmTitle: 'Выключить устройство?', + shutdownConfirmBody: 'Выключить «{{hostname}}»? Для повторного включения потребуется физический доступ.', + commandConfirm: 'Подтвердить', + commandQueued: 'Команда поставлена в очередь', + commandError: 'Не удалось отправить команду', + }, + ldap: { + title: 'Аутентификация LDAP', + enabledDesc: 'Аутентификация LDAP включена', + disabledDesc: 'Аутентификация LDAP отключена', + disabledHint: 'Настройте и сохраните параметры LDAP ниже, затем включите аутентификацию.', + enabled: 'Аутентификация LDAP включена', + disabled: 'Аутентификация LDAP отключена', + feature1: 'Пользователи могут входить с учётными данными LDAP', + feature2: 'Локальная учётная запись администратора остаётся резервным способом входа', + feature3: 'При входе группы LDAP сопоставляются с группами Bambuddy', + serverConfig: 'Настройка сервера LDAP', + serverUrl: 'Адрес сервера', + serverUrlHint: 'Используйте ldaps:// для SSL либо ldap:// с StartTLS', + security: 'Безопасность', + securityHint: 'StartTLS переводит обычное соединение на TLS. LDAPS использует TLS с самого начала.', + bindDn: 'Bind DN (служебная учётная запись)', + bindPassword: 'Пароль Bind', + searchBase: 'Базовый DN поиска', + userFilter: 'Фильтр поиска пользователей', + userFilterHint: '{username} заменяется именем пользователя при входе. Для OpenLDAP используйте (uid={username}).', + advanced: 'Дополнительно', + autoProvision: 'Автоматически создавать пользователей', + autoProvisionHint: 'Автоматически создавать учётную запись Bambuddy при первом входе через LDAP', + defaultGroup: 'Группа по умолчанию', + defaultGroupNone: '— Нет (без резервной группы) —', + defaultGroupHint: 'Резервная группа для пользователя LDAP, который успешно вошёл, но не состоит ни в одной сопоставленной группе LDAP. Оставьте пустым, чтобы такие пользователи не получали разрешений.', + groupMapping: 'Сопоставление групп (JSON)', + groupMappingHint: 'Сопоставьте DN групп LDAP с группами Bambuddy. Доступные группы: ', + testConnection: 'Проверить подключение', + settingsSaved: 'Настройки LDAP сохранены', + errors: { + serverRequired: 'Укажите адрес сервера LDAP', + searchBaseRequired: 'Укажите базовый DN поиска', + enableAuthFirst: 'Сначала включите аутентификацию', + configureLdapFirst: 'Сначала сохраните настройки LDAP', + }, + }, + email: { + smtpSettings: 'Настройка SMTP', + smtpHost: 'SMTP-сервер', + smtpPort: 'Порт SMTP', + security: 'Безопасность', + authentication: 'Аутентификация', + username: 'Имя пользователя', + password: 'Пароль', + fromEmail: 'Адрес отправителя', + fromName: 'Имя отправителя', + testConnection: 'Проверить подключение SMTP', + testRecipient: 'Адрес получателя тестового письма', + sendTest: 'Отправить тестовое письмо', + sending: 'Отправка...', + save: 'Сохранить настройки', + saving: 'Сохранение...', + advancedAuth: 'Расширенная аутентификация', + advancedAuthEnabled: 'Расширенная аутентификация включена', + advancedAuthEnabledDesc: 'Функции управления пользователями через email активны. Новые пользователи получают автоматически созданные пароли по почте и могут сбрасывать пароль через функцию восстановления.', + advancedAuthDisabled: 'Расширенная аутентификация отключена', + advancedAuthDisabledDesc: 'Включите расширенную аутентификацию, чтобы использовать почтовые функции управления пользователями.', + enable: 'Включить', + disable: 'Отключить', + feature1: 'Пароли для новых пользователей создаются автоматически и отправляются по email', + feature2: 'Пользователи могут входить по имени или адресу электронной почты', + feature3: 'Доступно восстановление забытого пароля', + feature4: 'Администраторы могут сбрасывать пароли пользователей по email', + errors: { + requiredFields: 'Заполните все обязательные поля', + usernameRequired: 'При включённой аутентификации требуется имя пользователя', + enterTestEmail: 'Введите адрес для тестового письма', + smtpServerAndEmail: 'Перед проверкой укажите SMTP-сервер и адрес отправителя', + usernamePasswordRequired: 'При включённой аутентификации требуются имя пользователя и пароль', + configureSmtpFirst: 'Сначала настройте и проверьте SMTP', + enableAuthFirst: 'Чтобы использовать почтовые функции, сначала включите аутентификацию.', + }, + success: { + settingsSaved: 'Настройки SMTP сохранены', + }, + securityOptions: { + starttls: 'STARTTLS (порт 587)', + ssl: 'SSL/TLS (порт 465)', + none: 'Без шифрования (порт 25)', + }, + authOptions: { + enabled: 'Включена', + disabled: 'Отключена', + }, + }, + appearance: 'Внешний вид', + notifications: 'Уведомления', + smartPlugs: 'Умные розетки', + spoolman: 'Spoolman', + updates: 'Обновления', + language: 'Язык', + languageDescription: 'Выберите предпочитаемый язык', + theme: 'Тема', + themeLight: 'Светлая', + themeDark: 'Тёмная', + themeSystem: 'Системная', + defaultView: 'Страница по умолчанию', + defaultViewDescription: 'Страница, которая открывается при запуске приложения', + checkForUpdates: 'Проверить обновления', + autoUpdate: 'Автоматическое обновление', + currentVersion: 'Текущая версия', + latestVersion: 'Последняя версия', + upToDate: 'Установлена последняя версия', + updateAvailable: 'Доступно обновление', + notificationLanguage: 'Язык уведомлений', + notificationLanguageDescription: 'Язык push-уведомлений', + bedCooledThreshold: 'Порог остывания стола', + bedCooledThresholdDescription: 'Температура, ниже которой стол после печати считается остывшим', + userNotificationsEnabled: 'Пользовательские уведомления', + userNotificationsEnabledDescription: 'Включить меню пользовательских и почтовых уведомлений о событиях печати. Требуется расширенная аутентификация.', + userNotificationsDisabledHint: 'Для пользовательских уведомлений включите расширенную аутентификацию.', + notificationProviders: 'Провайдеры уведомлений', + addProvider: 'Добавить провайдера', + editProvider: 'Изменить провайдера', + providerType: 'Тип провайдера', + testNotification: 'Проверить уведомление', + testSuccess: 'Тестовое уведомление успешно отправлено', + testFailed: 'Не удалось отправить тестовое уведомление', + quietHours: 'Тихие часы', + quietHoursDescription: 'Не беспокоить в указанный период', + quietHoursStart: 'Начало', + quietHoursEnd: 'Окончание', + events: { + title: 'События уведомлений', + printStart: 'Печать началась', + printComplete: 'Печать завершена', + printFailed: 'Ошибка печати', + printStopped: 'Печать остановлена', + printProgress: 'Этапы выполнения', + printProgressDescription: 'Уведомлять при 25%, 50% и 75%', + printerOffline: 'Принтер не в сети', + printerError: 'Ошибка принтера', + filamentLow: 'Филамент заканчивается', + maintenanceDue: 'Требуется обслуживание', + maintenanceDueDescription: 'Уведомлять, когда наступил срок обслуживания', + }, + smartPlug: { + title: 'Умные розетки', + add: 'Добавить умную розетку', + edit: 'Изменить умную розетку', + name: 'Название', + ipAddress: 'IP-адрес', + linkedPrinter: 'Связанный принтер', + autoOn: 'Автоматическое включение', + autoOnDescription: 'Включать при начале печати', + autoOff: 'Автоматическое выключение', + autoOffDescription: 'Выключать после завершения печати', + offDelay: 'Задержка выключения', + offDelayMinutes: 'Минут после печати', + offDelayTemp: 'Когда сопло остынет ниже заданной температуры', + currentState: 'Текущее состояние', + turnOn: 'Включить', + turnOff: 'Выключить', + }, + filamentTracking: 'Учёт филамента', + filamentTrackingDesc: 'Выберите способ учёта катушек: встроенный инвентарь или внешний сервер Spoolman.', + autoAddUnknownRfid: 'Автоматически добавлять неизвестные RFID-катушки', + autoAddUnknownRfidDesc: 'Автоматически создавать запись в инвентаре при обнаружении катушки с неизвестной RFID-меткой. Отключите, если регистрируете новые катушки заранее, чтобы избежать дубликатов.', + filamentChecks: 'Проверки филамента', + disableFilamentWarnings: 'Отключить предупреждения о филаменте', + disableFilamentWarningsDesc: 'Не показывать предупреждения о нехватке филамента при запуске печати или добавлении в очередь', + preferLowestFilament: 'Предпочитать катушку с наименьшим остатком', + preferLowestFilamentDesc: 'Если подходят несколько катушек, использовать катушку с наименьшим остатком филамента', + preferLowestFilamentBackupNote: 'Работает только при включённом AMS Filament Backup: иначе принтер не сможет переключиться на вторую катушку после окончания выбранной.', + trackingModeBuiltIn: 'Встроенный инвентарь', + trackingModeBuiltInDesc: 'Автоматическое сопоставление RFID и учёт расхода', + trackingModeSpoolmanDesc: 'Внешний сервер управления филаментом', + builtInFeatureRfid: 'Автоматически определяет официальные RFID-катушки Bambu Lab в AMS', + builtInFeatureUsage: 'Учитывает расход филамента для каждой печати', + builtInFeatureCatalog: 'Управление катушками, цветами и профилями K-фактора', + builtInFeatureThirdParty: 'Сторонние катушки можно связать с катушками инвентаря', + amsSyncButton: 'Синхронизировать вес из AMS', + amsSyncTitle: 'Синхронизация веса катушек из AMS', + amsSyncMessage: 'Вес всех катушек инвентаря будет заменён текущими значениями остатка из AMS подключённых принтеров. Используйте это для восстановления повреждённых данных о весе. Принтеры должны быть в сети.', + amsSyncing: 'Синхронизация...', + amsSyncSuccess: 'Синхронизировано катушек: {{synced}}, пропущено: {{skipped}}', + amsSyncError: 'Не удалось синхронизировать вес из AMS', + spoolmanAmsSyncButton: 'Синхронизировать вес Spoolman из AMS', + spoolmanAmsSyncTitle: 'Синхронизация веса катушек Spoolman из AMS', + spoolmanAmsSyncMessage: 'Вес всех катушек Spoolman будет обновлён по текущим значениям остатка из AMS подключённых принтеров. Принтеры должны быть в сети.', + spoolmanAmsSyncing: 'Синхронизация...', + spoolmanAmsSyncSuccess: 'Синхронизировано катушек: {{synced}}, пропущено: {{skipped}}', + spoolmanAmsSyncError: 'Не удалось синхронизировать вес Spoolman из AMS', + spoolmanAmsSyncErrorUnreachable: 'Не удалось синхронизировать вес Spoolman: сервер недоступен', + spoolmanAmsSyncErrorNotConfigured: 'Не удалось синхронизировать вес Spoolman: сервер не настроен', + spoolmanNotConfigured: 'Spoolman не настроен', + spoolmanFilamentCatalogTitle: 'Каталог филамента Spoolman', + spoolmanFilamentCatalogDesc: 'Названия филаментов и масса пустых катушек из Spoolman. Здесь можно изменить название и массу катушки; остальные свойства редактируются непосредственно в Spoolman.', + spoolmanUrl: 'Адрес Spoolman', + spoolmanUrlHint: 'Адрес сервера Spoolman, например http://localhost:7912', + spoolmanConnected: 'Подключён', + spoolmanDisconnected: 'Отключён', + status: 'Состояние', + connect: 'Подключить', + disconnect: 'Отключить', + howSyncWorks: 'Как работает синхронизация', + syncInfoRfidOnly: 'Синхронизируются только официальные RFID-катушки Bambu Lab', + syncInfoAutoCreate: 'Новые катушки автоматически создаются в Spoolman при первой синхронизации', + syncInfoThirdPartySkipped: 'Неофициальные катушки Bambu Lab, сторонние и перезаправленные катушки пропускаются', + oidc: { + title: 'Провайдеры SSO / OIDC', + desc: 'Настройка провайдеров OpenID Connect для единого входа через внешние службы идентификации.', + addProvider: 'Добавить провайдера', + newProvider: 'Новый провайдер', + empty: 'Провайдеры OIDC пока не настроены.', + created: 'Провайдер создан.', + updated: 'Провайдер обновлён.', + deleted: 'Провайдер удалён.', + refreshIcon: 'Обновить значок', + removeIcon: 'Удалить значок', + iconRefreshed: 'Значок обновлён.', + iconRemoved: 'Значок удалён.', + iconFetchFailed: 'Не удалось получить значок по URL провайдера.', + deleteTitle: 'Удалить провайдера', + deleteMessage: 'Удалить «{{name}}»? Все связанные учётные записи пользователей будут отсоединены.', + form: { + name: 'Отображаемое имя', + issuerUrl: 'URL издателя', + clientId: 'Идентификатор клиента', + clientSecret: 'Секрет клиента', + scopes: 'Области доступа', + iconUrl: 'URL значка (необязательно)', + enabled: 'Включён', + autoCreate: 'Автоматически создавать пользователей', + autoCreateDesc: 'Автоматически создавать локальную учётную запись при первом входе.', + autoLink: 'Автоматически связывать существующие учётные записи', + autoLinkDesc: 'При первом входе связывать локальные учётные записи по совпадающему адресу электронной почты.', + secretHint: 'оставьте пустым, чтобы сохранить текущий', + secretPlaceholder: 'новый секрет', + emailClaim: 'Поле электронной почты', + emailClaimDesc: 'Поле JWT, используемое как адрес электронной почты. Для Azure Entra ID, который не передаёт email_verified, используйте preferred_username или upn. Указывайте только доверенные поля.', + emailClaimPlaceholder: 'email', + emailClaimCustomClaimAutoLinkWarning: 'Пользовательское поле безопасно для автоматического связывания только тогда, когда его значение назначается администратором арендатора, например upn или preferred_username в Azure Entra ID. Не включайте автоматическое связывание, если ваш IdP позволяет пользователям самостоятельно задавать это поле.', + requireEmailVerified: 'Требовать подтверждённый адрес электронной почты', + requireEmailVerifiedDesc: 'Принимать адрес электронной почты только в том случае, если провайдер пометил его как подтверждённый.', + requireEmailVerifiedWarning: 'Предупреждение: адрес будет принят даже без подтверждения. Используйте только с доверенными провайдерами.', + requireEmailVerifiedAutoLink: 'Чтобы изменить этот параметр, сначала отключите автоматическое связывание.', + defaultGroup: 'Группа по умолчанию', + defaultGroupDesc: 'Группа для автоматически созданных пользователей. Если не задана, используется группа «Наблюдатели».', + defaultGroupViewersFallback: 'Наблюдатели (по умолчанию)', + autologin: 'Автоматический вход', + autologinDesc: 'Сразу перенаправлять неавторизованных посетителей к этому провайдеру. Этот флаг может быть установлен только у одного провайдера.', + }, + }, + twoFa: { + totpTitle: 'Приложение-аутентификатор (TOTP)', + totpDesc: 'Использовать приложение-аутентификатор, например Google Authenticator, Aegis или Authy.', + emailOtpTitle: 'Одноразовый код по электронной почте', + emailOtpDesc: 'Отправлять одноразовый код на {{email}} при входе.', + emailOtpNoEmail: 'Добавьте адрес электронной почты в учётную запись, чтобы включить этот способ.', + addEmailFirst: 'В вашей учётной записи нет адреса электронной почты. Перед включением одноразовых кодов попросите администратора добавить его.', + setupTotp: 'Настроить приложение-аутентификатор', + setupAuthApp: 'Настроить приложение-аутентификатор', + setupInstructions: 'Отсканируйте QR-код приложением-аутентификатором, затем подтвердите настройку кодом.', + manualEntry: 'Не получается отсканировать? Введите этот секрет вручную:', + scannedContinue: 'Код отсканирован — продолжить', + enterCodeToConfirm: 'Для подтверждения настройки введите шестизначный код из приложения-аутентификатора.', + activate: 'Активировать', + disableTotp: 'Отключить аутентификатор', + disableConfirmHint: 'Чтобы отключить аутентификатор, введите действующий код TOTP или резервный код.', + totpDisabled: 'Приложение-аутентификатор отключено.', + emailOtpEnabled: 'Одноразовые коды по электронной почте включены.', + emailOtpDisabled: 'Одноразовые коды по электронной почте отключены.', + smtpRequired: 'Сначала настройте и проверьте SMTP.', + invalidCode: 'Неверный код. Повторите попытку.', + enableEmailOtp: 'Включить одноразовые коды по электронной почте', + disableEmailOtp: 'Отключить одноразовые коды по электронной почте', + emailSetupEnterCode: 'Код подтверждения отправлен на вашу электронную почту. Введите его ниже, чтобы подтвердить доступ к этому почтовому ящику.', + verifyAndEnable: 'Подтвердить и включить', + emailDisablePasswordHint: 'Чтобы подтвердить отключение одноразовых кодов по электронной почте, введите пароль учётной записи.', + passwordPlaceholder: 'Введите пароль', + backupCodesTitle: 'Сохраните резервные коды', + backupCodesWarning: 'Сохраните эти коды в надёжном месте. Каждый код можно использовать только один раз; повторно они показаны не будут.', + backupCodesRemaining: 'Осталось резервных кодов: {{count}}', + savedCodes: 'Я сохранил коды', + regenBackup: 'Создать новые резервные коды', + regenBackupHint: 'Введите текущий код TOTP, чтобы создать 10 новых резервных кодов. Все существующие резервные коды станут недействительными.', + newBackupCodes: 'Новые резервные коды', + linkedAccounts: 'Связанные учётные записи SSO', + linkedAccountsDesc: 'Эти внешние провайдеры идентификации связаны с вашей учётной записью.', + oidcUnlinked: 'Учётная запись отсоединена.', + }, + encryption: { + title: 'Состояние шифрования MFA', + enabledFromEnv: 'Шифрование данных включено; ключ получен из переменной окружения MFA_ENCRYPTION_KEY', + enabledFromFile: 'Шифрование данных включено; ключ загружен из каталога данных', + enabledGenerated: 'Шифрование данных включено с автоматически созданным ключом', + notConfigured: 'Шифрование хранимых данных не настроено', + notConfiguredDesc: 'Секреты TOTP и client_secret провайдеров OIDC хранятся открытым текстом. Задайте MFA_ENCRYPTION_KEY или перезапустите Bambuddy с доступным для записи каталогом данных, чтобы ключ был создан автоматически.', + allEncrypted: 'Все секреты MFA зашифрованы при хранении.', + legacyRowsLabel: 'Старые записи открытым текстом', + encryptedRowsLabel: 'Зашифрованные записи', + legacyRowsWarning: 'Обнаружено старых записей открытым текстом: {{count}}. Чтобы перенести их в зашифрованное хранилище, повторно сохраните провайдера OIDC или заново подключите приложение-аутентификатор пользователя.', + backupHint: 'Автоматически созданный ключ хранится в DATA_DIR/.mfa_encryption_key и включается в локальные ZIP-копии. Храните резервные копии в безопасном месте либо задайте MFA_ENCRYPTION_KEY явно.', + decryptionBrokenTitle: 'Отсутствует ключ шифрования', + decryptionBrokenError: 'Невозможно расшифровать записей: {{count}}, поскольку ключ шифрования больше недоступен. Для восстановления верните прежний MFA_ENCRYPTION_KEY или файл DATA_DIR/.mfa_encryption_key.', + migrationErrorWarning: 'Не удалось повторно зашифровать старых записей при запуске: {{count}}. Проверьте журнал сервера и перезапустите Bambuddy для повторной попытки.', + }, + sessionPolicy: { + title: 'Политика сеансов', + description: 'Максимальный срок действия сеанса для новых входов пользователей. Уже выданные токены сохраняют исходный срок действия.', + preset24h: '24 часа', + preset7d: '7 дней', + preset30d: '30 дней', + customHoursLabel: 'Срок действия сеанса в часах', + hoursSuffix: 'часов', + warning: 'Длительные сеансы снижают защиту автоматическим выходом. Рекомендуется только для доверенных установок с одним пользователем.', + }, + webhook: { + getAllStatus: 'Получить состояние всех принтеров', + getSpecificStatus: 'Получить состояние выбранного принтера', + addToQueue: 'Добавить в очередь печати', + pausePrint: 'Приостановить печать', + resumePrint: 'Продолжить печать', + stopPrint: 'Остановить печать', + }, + pipelines: { + title: 'Конвейеры слайсера', + subtitle: 'Повторно используемые наборы профилей: принтер, процесс, филаменты и тип стола. Сохраните набор в окне нарезки и применяйте его к следующему файлу одним нажатием.', + loading: 'Загрузка конвейеров...', + loadError: 'Не удалось загрузить конвейеры.', + confirmDelete: 'Удалить этот конвейер? Отменить действие нельзя.', + staleWarning: 'Один или несколько связанных профилей больше не существуют. Чтобы исправить конвейер, повторно сохраните его из окна нарезки.', + empty: { + title: 'Конвейеров пока нет.', + howto: 'Откройте окно нарезки любого файла, выберите принтер, процесс, филаменты и тип стола, затем нажмите «Сохранить как конвейер». Сохранённые конвейеры появятся здесь.', + }, + field: { + name: 'Название конвейера', + description: 'Описание', + targetPrinter: 'Целевой принтер', + noTarget: '— Цель не задана —', + targetKind: 'Тип цели', + targetKindSpecific: 'Конкретный принтер', + targetKindClass: 'Класс принтеров', + targetModelClass: 'Модель принтера', + fanoutStrategy: 'Стратегия распределения', + fanout: { + max_parallel: 'Максимум параллельно — распределять между любыми свободными подходящими принтерами', + round_robin: 'По кругу — последовательно чередовать подходящие принтеры', + fill_one_first: 'Сначала один — назначить все копии одному принтеру', + }, + fanoutShort: { + max_parallel: 'параллельно', + round_robin: 'по кругу', + fill_one_first: 'сначала один', + }, + }, + action: { + save: 'Сохранить', + cancel: 'Отмена', + rename: 'Переименовать', + delete: 'Удалить', + }, + slot: { + printer: 'Принтер', + process: 'Процесс', + filament: 'Филамент', + filamentN: 'Филамент {{n}}', + filamentAll: 'Все слоты: {{n}}', + bed: 'Стол', + }, + group: { + profiles: 'Профили', + filaments: 'Филаменты', + }, + searchPlaceholder: 'Поиск конвейеров...', + filterTargetType: 'Фильтр по типу цели', + filterTarget: 'Фильтр по цели', + filter: { + all: 'Все цели', + noTarget: 'Цель не задана', + count: '{{shown}} из {{total}}', + noMatches: 'Нет конвейеров, соответствующих текущим фильтрам.', + }, + toast: { + saved: 'Конвейер сохранён', + saveFailed: 'Не удалось сохранить', + deleted: 'Конвейер удалён', + deleteFailed: 'Не удалось удалить', + }, + noTargetHint: 'Чтобы запустить, задайте целевой принтер', + noTargetWarning: 'Перед запуском конвейера задайте целевой принтер.', + runs: { + lastRun: 'Последний запуск', + status: { + queued: 'в очереди', + slicing: 'нарезка', + dispatching: 'назначение', + in_progress: 'печать', + completed: 'завершено', + failed: 'ошибка', + partial_failure: 'частичная ошибка', + cancelled: 'отменено', + }, + }, + }, + pipelineLimits: { + title: 'Ограничения конвейеров слайсера', + maxCopiesLabel: 'Максимум копий за запуск', + maxCopiesDesc: 'Верхний предел количества копий, которое оператор может запросить при запуске конвейера. Жёсткое серверное ограничение — 1000.', + }, + slicerBundlesRemoved: { + title: 'Пакеты профилей слайсера (удалено)', + description: 'Импорт пакетов профилей принтера .bbscfg удалён. Экспорт пакета из BambuStudio содержит только пользовательские профили, поэтому стандартные процессы и филаменты не импортировались, а нарезка использовала встроенные настройки.', + alternatives: 'Для отдельных пользовательских профилей используйте импорт одного профиля либо синхронизацию через Bambu Cloud или Orca Cloud. Стандартные профили автоматически предоставляет служба слайсера.', + lookupOrder: 'Порядок поиска профиля при нарезке: 1) импортированный локально, 2) Orca Cloud, 3) Bambu Cloud, 4) стандартный профиль службы слайсера.', + }, + linkingExistingSpools: 'Привязка существующих катушек', + linkingExistingSpoolsDesc: 'Чтобы привязать существующую катушку Spoolman к AMS, наведите указатель на слот AMS и нажмите «Привязать к Spoolman».', + syncMode: 'Режим синхронизации', + syncModeAuto: 'Автоматически', + syncModeManual: 'Только вручную', + syncModeAutoDesc: 'Данные AMS синхронизируются автоматически при обнаружении изменений', + syncModeManualDesc: 'Синхронизация выполняется только вручную', + syncAmsData: 'Синхронизировать данные AMS', + syncAmsDataDesc: 'Вручную синхронизировать данные AMS принтера со Spoolman', + allPrinters: 'Все принтеры', + noDefaultPrinter: 'Без принтера по умолчанию (спрашивать каждый раз)', + sidebarOrder: 'Порядок пунктов боковой панели', + saveThumbnails: 'Сохранять миниатюры', + captureFinishPhoto: 'Снимок после завершения', + noPrintersConfigured: 'Принтеры не настроены', + archiveMode: { + always: 'Всегда создавать запись в архиве', + never: 'Не создавать запись в архиве', + ask: 'Спрашивать каждый раз', + }, + checkForUpdatesLabel: 'Проверять обновления', + checkPrinterFirmware: 'Проверять прошивку принтера', + includeBetaUpdates: 'Включать бета-версии', + includeBetaUpdatesDesc: 'Уведомлять о бета- и предварительных версиях при проверке обновлений', + localLogin: { + disable: 'Отключить локальный вход по имени пользователя и паролю', + disableHint: 'Если включено, вход возможен только через провайдеров SSO. На LDAP это не влияет. Чтобы сохранить аварийный способ входа, задайте на сервере BAMBUDDY_LOCAL_LOGIN=true.', + }, + enableRetry: 'Включить повторные попытки', + homeAssistantDescription: 'Управление умными розетками через Home Assistant', + environmentManagedLabel: '(управляется окружением)', + autoEnabledViaEnv: 'Автоматически включено переменными окружения', + urlFromEnvReadOnly: 'Значение задано переменной окружения HA_URL (только чтение)', + tokenFromEnvReadOnly: 'Значение задано переменной окружения HA_TOKEN (только чтение)', + mqttConnectedTo: 'Подключено к', + prometheusDescription: 'Экспортировать данные принтеров в формате Prometheus', + noSmartPlugsTitle: 'Умные розетки не настроены', + noSmartPlugsDescription: 'Добавьте умную розетку на базе Tasmota для учёта энергии и автоматизации питания.', + noProvidersTitle: 'Провайдеры не настроены', + noProvidersDescription: 'Добавьте провайдера для получения уведомлений.', + noTemplatesAvailable: 'Шаблоны отсутствуют. Перезапустите бэкенд, чтобы создать стандартные шаблоны.', + apiPermissionView: 'Просмотр состояния принтеров и очереди', + apiPermissionEdit: 'Добавление и удаление заданий из очереди печати', + apiKeysEmptyTitle: 'Ключей API нет', + apiKeysEmptyDescription: 'Создайте ключ API для интеграции с внешними сервисами.', + noUsersFound: 'Пользователи не найдены', + noGroupsFound: 'Группы не найдены', + noGroupsAvailable: 'Доступных групп нет', + passwordsDoNotMatch: 'Пароли не совпадают', + systemGroupWarning: 'Названия системных групп изменить нельзя', + authDisabledTitle: 'Аутентификация отключена', + authDisabledFeature1: 'Требовать вход для доступа к системе', + authDisabledFeature2: 'Создавать нескольких пользователей с групповыми разрешениями', + authDisabledFeature3: 'Управлять доступом с помощью более чем 50 отдельных разрешений', + userHasCreated: 'Этот пользователь создал:', + userItemsQuestion: 'Что сделать с этими объектами?', + deleteUserConfirm: 'Удалить этого пользователя?', + actionCannotBeUndone: 'Это действие нельзя отменить.', + addFirstSmartPlug: 'Добавить первую умную розетку', + providers: 'Провайдеры', + log: 'Журнал', + testAll: 'Проверить все', + testResults: 'Результаты проверки', + testPassedCount: 'Успешно: {{count}}', + testFailedCount: 'Ошибок: {{count}}', + messageTemplates: 'Шаблоны сообщений', + messageTemplatesDescription: 'Настройте тексты уведомлений для каждого события.', + apiKeys: 'Ключи API', + apiKeysDescription: 'Создавайте ключи API для внешних интеграций и вебхуков.', + createKey: 'Создать ключ', + apiKeyCreated: 'Ключ API успешно создан', + apiKeyCopyWarning: 'Скопируйте ключ сейчас — повторно он показан не будет!', + useInApiBrowser: 'Использовать в обозревателе API', + apiKeyQrButton: 'QR-код', + apiKeyQrTitle: 'Сканирование для настройки', + apiKeyQrCaption: 'Отсканируйте мобильным приложением, чтобы добавить этот сервер и ключ API.', + apiKeyQrWarning: 'QR-код содержит секретный ключ API — не передавайте его и не публикуйте снимок экрана.', + createNewApiKey: 'Создать ключ API', + keyName: 'Название ключа', + keyNamePlaceholder: 'например, Home Assistant или OctoPrint', + readStatus: 'Чтение состояния', + readStatusDescription: 'Просмотр состояния принтеров и очереди', + manageQueue: 'Управление очередью', + manageQueueDescription: 'Добавление и удаление заданий из очереди печати', + controlPrinter: 'Управление принтером', + controlPrinterDescription: 'Пауза, продолжение и остановка печати', + manageLibrary: 'Управление библиотекой', + manageLibraryDescription: 'Загрузка, переименование и удаление файлов библиотеки; импорт моделей из MakerWorld', + manageInventory: 'Управление запасами', + manageInventoryDescription: 'Создание, изменение и удаление катушек и записей учёта. Требуется для киосков SpoolBuddy: сканирование NFC, показания весов и системные команды киоска.', + manageMaintenance: 'Управление обслуживанием', + manageMaintenanceDescription: 'Регистрация выполненного обслуживания, сброс счётчиков, изменение интервалов и управление каталогом видов обслуживания. Подходит для автоматизаций Home Assistant, которые отмечают, например, «сопло очищено», без предоставления более широких прав управления принтером.', + manageArchives: 'Управление архивом', + manageArchivesDescription: 'Изменение и удаление записей архива печати, включая старые задания. Не включает удаление их вклада в статистику. Подходит для автоматизаций очистки истории печати.', + manageProjects: 'Управление проектами', + manageProjectsDescription: 'Создание, изменение и удаление проектов, а также добавление в них архивных заданий. Подходит для автоматизаций, распределяющих печати по проектам.', + libraryBadge: 'Библиотека', + inventoryBadge: 'Запасы', + maintenanceBadge: 'Обслуживание', + archivesBadge: 'Архив', + projectsBadge: 'Проекты', + cloudAccess: 'Разрешить доступ к облаку', + cloudAccessDescription: 'Чтение пресетов и филаментов Bambu Cloud от вашего имени. Требуется вход в Bambu Cloud.', + cloudBadge: 'Облако', + updateEnergyCost: 'Обновление тарифа на электроэнергию', + updateEnergyCostDescription: 'Разрешить этому ключу отправлять новую цену за кВт⋅ч методом POST в /settings/electricity-price. Полезно для автоматизаций динамического тарифа Home Assistant (Tibber, Octopus и т. п.). Это единственный параметр настроек, доступный для записи через ключ API.', + energyCostBadge: 'Энергия', + legacyKey: 'Устаревший', + legacyKeyTooltip: 'Создан до появления привязки к пользователям; пересоздайте для доступа к облаку', + unnamedKey: 'Ключ без названия', + lastUsed: 'Последнее использование', + read: 'Чтение', + control: 'Управление', + createFirstKey: 'Создать первый ключ', + webhookEndpoints: 'Конечные точки вебхуков', + webhookApiKeyHint: 'Передавайте ключ API в заголовке X-API-Key.', + apiBrowser: 'Обозреватель API', + apiBrowserDescription: 'Просмотр и проверка всех доступных конечных точек API.', + apiKeyForTesting: 'Ключ API для проверки', + apiKeyPlaceholder: 'Вставьте ключ API для проверки защищённых конечных точек…', + apiKeyHint: 'Ключ будет передан в запросе в заголовке X-API-Key.', + deleteApiKeyTitle: 'Удаление ключа API', + deleteApiKeyMessage: 'Удалить этот ключ API? Все использующие его интеграции перестанут работать.', + deleteKey: 'Удалить ключ', + amsDisplayThresholds: 'Пороговые значения AMS', + amsThresholdsDescription: 'Настройте цветовые пороги индикаторов влажности и температуры AMS.', + humidity: 'Влажность', + goodGreen: 'Норма (зелёный)', + fairOrange: 'Допустимо (оранжевый)', + aboveFairBad: 'Выше допустимого порога отображается красным', + fairAlsoDryingThreshold: 'Этот порог также запускает автоматическую сушку, если она включена', + temperature: 'Температура', + goodBlue: 'Норма (синий)', + aboveFairHot: 'Выше допустимого порога отображается красным как перегрев', + historyRetention: 'Хранение истории', + keepSensorHistory: 'Хранить историю датчиков', + historyRetentionDescription: 'Более старые данные влажности и температуры будут удаляться автоматически', + defaultPrintOptions: 'Параметры печати по умолчанию', + defaultPrintOptionsDescription: 'Задайте значения по умолчанию для новых заданий. Их можно изменить отдельно в диалоге запуска печати.', + defaultBedLevelling: 'Калибровка стола', + defaultBedLevellingDesc: 'Автоматически выровнять стол перед печатью', + defaultFlowCali: 'Калибровка потока', + defaultFlowCaliDesc: 'Калибровать поток экструзии', + defaultVibrationCali: 'Калибровка вибраций', + defaultVibrationCaliDesc: 'Уменьшить артефакты звона', + defaultLayerInspect: 'Проверка первого слоя', + defaultLayerInspectDesc: 'Проверка первого слоя системой компьютерного зрения', + defaultTimelapse: 'Таймлапс', + defaultTimelapseDesc: 'Записывать таймлапс', + defaultNozzleOffsetCali: 'Калибровка смещения сопел', + defaultNozzleOffsetCaliDesc: 'Калибровать взаимное смещение сопел экструдеров', + tempFanPresetsTitle: 'Пресеты температуры и вентиляторов', + tempFanPresetsDescription: 'Настройте значения быстрого выбора в меню температуры и скорости вентиляторов карточки принтера. Кнопка «Выкл.» отображается всегда.', + tempFanPresetsNozzle: 'Температура сопла', + tempFanPresetsBed: 'Температура стола', + tempFanPresetsChamber: 'Температура камеры', + tempFanPresetsFan: 'Скорость вентилятора', + tempFanPresetsReset: 'Восстановить значения по умолчанию', + staggeredStart: 'Поэтапный запуск', + staggeredStartDescription: 'Размер группы и интервал по умолчанию при поэтапном запуске партии на нескольких принтерах. Для каждой партии значения можно изменить в окне запуска печати.', + preheatTitle: 'Преднагрев и выдержка', + preheatDescription: 'Нагреть стол и, если поддерживается, камеру, затем выдержать температуру перед запуском каждого задания очереди. Полезно для инженерных пластиков (PA, ABS) на принтерах без активного нагревателя камеры: во время выдержки стол прогревает камеру излучением. Целевая температура стола берётся из файла печати; поведение камеры зависит от модели принтера.', + preheatEnabled: 'Включить преднагрев и выдержку', + preheatEnabledDesc: 'Если выключено, задания очереди отправляются сразу. Для каждого задания можно задать отдельное значение.', + preheatFilamentTargetsLabel: 'Целевая температура камеры по типу филамента (°C)', + preheatFilamentTargetsHint: 'Bambuddy выбирает наибольшее значение среди задействованных слотов AMS; для печати только PLA автоматически используется 0 и этап прогрева камеры пропускается.', + preheatFilamentTargetsReset: 'Восстановить значения по умолчанию', + preheatFilamentTargetsDefaultRow: 'Прочее / без сопоставления', + preheatMaxWait: 'Максимальное ожидание (с)', + preheatMaxWaitHelp: 'Предельное время прогрева камеры, после которого процесс продолжится.', + preheatSoak: 'Выдержка (с)', + preheatSoakHelp: 'Время выдержки после достижения цели или истечения максимального ожидания.', + preheatHardwareTitle: 'Поведение по моделям принтеров:', + preheatHardwareDetail: 'H2C/H2D/H2D Pro/H2S/X2D/X1E активно нагревают камеру командой M141. X1C/P2S измеряют температуру камеры, но прогревают её только теплом стола. У P1S/P1P/A1/A1 Mini нет датчика камеры — применяется только таймер выдержки.', + preheatPerItemDesc: 'Нагревать стол и камеру перед запуском этого задания. По умолчанию используется общий переключатель «Настройки → Рабочий процесс».', + preheatOverride_inherit: 'Наследовать', + preheatOverride_on: 'Включено', + preheatOverride_off: 'Выключено', + preheatTargetOverride: 'Переопределение температуры камеры (°C; пусто — значение для филамента)', + plateClear: 'Подтверждение очистки пластины', + requirePlateClear: 'Требовать подтверждение очистки пластины', + requirePlateClearDescription: 'Если включено, планировщик не запускает следующее задание на принтере с завершённой печатью, пока не подтверждена очистка пластины. Отключение также скрывает индикатор состояния пластины и кнопку «Пластина очищена» на карточках принтеров.', + gcodeInjection: 'Вставка G-кода', + gcodeInjectionDescription: 'Настройте G-код, добавляемый в начало и/или конец печати для систем автоматического запуска, таких как Farmloop, SwapMod, AutoClear и Printflow 3D. Фрагменты задаются отдельно для каждой модели принтера и применяются, когда для задания очереди включена вставка G-кода.', + gcodeInjectionNoPrinters: 'Принтеры не найдены. Добавьте принтеры, чтобы настроить фрагменты G-кода.', + gcodeStartLabel: 'Начальный G-код', + gcodeEndLabel: 'Завершающий G-код', + gcodeStartPlaceholder: 'G-код, добавляемый перед началом печати…', + gcodeEndPlaceholder: 'G-код, добавляемый после завершения печати…', + staggerGroupSize: 'Размер группы', + staggerGroupSizeHelp: 'Количество принтеров, запускаемых одновременно', + staggerInterval: 'Интервал (мин)', + staggerIntervalHelp: 'Задержка между запуском групп', + queueDrying: 'Автоматическая сушка в очереди', + queueDryingDescription: 'Автоматически сушить филамент в AMS, когда принтер простаивает между заданиями очереди. Запуск определяется указанным выше порогом влажности.', + queueDryingEnabled: 'Включить автоматическую сушку', + queueDryingEnabledDescription: 'Автоматически запускать сушку AMS, когда принтер простаивает и влажность выше порога', + queueDryingBlock: 'Ожидать завершения сушки', + queueDryingBlockDescription: 'Блокировать очередь печати до завершения сушки. Если выключено, печать имеет приоритет.', + ambientDryingEnabled: 'Фоновая сушка', + ambientDryingEnabledDescription: 'Автоматически сушить филамент на простаивающих принтерах при превышении порога влажности, даже если очередь пуста.', + printDryingEnabled: 'Продолжать сушку во время печати', + printDryingEnabledDescription: 'Разрешить автоматической сушке продолжаться во время печати на поддерживаемом оборудовании (H2D, H2C, H2S, P2S, H2D Pro, X2D, X1C, A2L с актуальной прошивкой). Для защиты катушек температура автоматически ограничивается на 5 °C ниже пресета сушки в простое.', + dryingPresets: 'Пресеты сушки', + dryingPresetsDescription: 'Температура и длительность для каждого типа филамента. AMS 2 Pro использует более низкие температуры, AMS-HT поддерживает более высокие.', + dryingFilament: 'Филамент', + humidityThresholds: 'Пороги влажности', + humidityThresholdsDescription: 'Порог запуска автоматической сушки и предупреждений для каждого типа филамента. При смешанной загрузке AMS используется наименьший порог.', + humidityThresholdCol: 'Порог', + humidityThresholdDefault: 'По умолчанию (неизвестные типы)', + printModal: 'Окно запуска печати', + expandCustomMapping: 'Разворачивать пользовательское сопоставление', + expandCustomMappingDescription: 'При печати на нескольких принтерах сразу показывать развёрнутое сопоставление AMS для каждого принтера', + authentication: 'Аутентификация', + authEnabledDescription: 'Доступ к экземпляру защищён аутентификацией пользователей', + authDisabledDescription: 'Включите, чтобы требовать вход и управлять доступом пользователей', + authDisabledMessage: 'Включите аутентификацию, чтобы создавать учётные записи, управлять правами и защитить экземпляр Bambuddy.', + enableAuthentication: 'Включить аутентификацию', + currentUser: 'Текущий пользователь', + changePassword: 'Изменить пароль', + admin: 'Администратор', + users: 'Пользователи', + addUser: 'Добавить пользователя', + groups: 'Группы', + addGroup: 'Добавить группу', + system: 'Система', + noDescription: 'Нет описания', + userCount: 'Пользователей: {{count}}', + permissionCount: 'Разрешений: {{count}}', + createUser: 'Создать пользователя', + username: 'Имя пользователя', + enterUsername: 'Введите имя пользователя', + password: 'Пароль', + enterPassword: 'Введите пароль', + passwordRequirements: 'Не менее 8 символов: одна заглавная и одна строчная буква, одна цифра и один специальный символ.', + confirmPassword: 'Подтвердите пароль', + confirmPasswordPlaceholder: 'Повторите пароль', + viewReleaseOnGitHub: 'Открыть выпуск на GitHub', + turnAllPlugsOn: 'Включить все розетки', + turnAllPlugsOff: 'Выключить все розетки', + clearNotificationLogs: 'Очистить журнал уведомлений', + clearLogsMessage: 'Все записи журнала уведомлений старше 30 дней будут безвозвратно удалены. Это действие нельзя отменить.', + clearLogs: 'Очистить журнал', + resetUiPreferences: 'Сбросить настройки интерфейса', + resetUiPreferencesMessage: 'Будут сброшены порядок боковой панели, тема, компоновка панели, режимы отображения и сортировка. Принтеры, архивы и серверные настройки НЕ изменятся. После очистки страница перезагрузится.', + resetPreferences: 'Сбросить настройки', + deleteGroupTitle: 'Удаление группы', + deleteGroupMessage: 'Удалить эту группу? Пользователи группы потеряют назначенные ей разрешения.', + deleteGroup: 'Удалить группу', + disableAuthenticationTitle: 'Отключение аутентификации', + disableAuthenticationMessage: 'Отключить аутентификацию? Bambuddy станет доступен без входа. Все пользователи останутся в базе данных, но проверка учётных данных выполняться не будет.', + disableAuthentication: 'Отключить аутентификацию', + configureBambuddy: 'Настроить Bambuddy', + systemDefault: 'Системное значение', + archiveSettings: 'Настройки архива', + newWindow: 'Новое окно', + embeddedOverlay: 'Встроенное наложение', + preferredSlicer: 'Предпочитаемый слайсер', + preferredSlicerDescription: 'Слайсер для нарезки внутри приложения через API-службу', + openInSlicerLabel: 'Открывать в слайсере', + openInSlicerInherit: 'Как для API-слайсера', + openInSlicerDescription: 'Настольный слайсер, который открывается кнопкой «Открыть в слайсере». Оставьте «Как для API-слайсера», чтобы наследовать настройку, либо выберите другой локальный слайсер.', + orcaslicerKnownIssuesWarning: 'В OrcaSlicer 2.3.2 и 2.4.0-dev известны ошибки CLI, мешающие нарезке многих 3MF от Bambu: #12426 (сбой на раскрашенных файлах с несколькими экструдерами) и #13386 (слишком строгая проверка диапазонов параметров). До исправления рекомендуется Bambu Studio.', + useSlicerApi: 'Использовать API слайсера', + useSlicerApiDescription: 'Если включено, действия «Нарезать» открывают встроенное окно и обращаются к API-службе слайсера. Если выключено, файл передаётся настольному слайсеру через URI-схему.', + slicerCard: 'Слайсер', + orcaslicerApiUrl: 'URL API-службы OrcaSlicer', + bambuStudioApiUrl: 'URL API-службы Bambu Studio', + slicerApiUrlDescription: 'URL контейнера API-службы слайсера. Оставьте пустым, чтобы использовать значения переменных окружения SLICER_API_URL или BAMBU_STUDIO_API_URL.', + externalCameras: 'Внешние камеры', + costTracking: 'Учёт затрат', + printsOnly: 'Только печать', + totalConsumption: 'Общее потребление', + dataManagement: 'Управление данными', + storageUsage: 'Использование хранилища', + storageUsageDescription: 'Распределение занятого места по категориям', + storageUsageTotal: 'Всего', + storageUsageErrors: 'Ошибки', + storageUsageOtherBreakdown: 'Прочее (статические ресурсы, скрипты и конфигурационные файлы)', + storageUsageSystem: 'Система', + storageUsageData: 'Данные', + storageUsageUnavailable: 'Сведения об использовании хранилища недоступны', + clearNotificationLogsDescription: 'Удалить записи журнала уведомлений старше 30 дней', + resetUiPreferencesDescription: 'Сбросить порядок боковой панели, тему, режимы отображения и компоновку. Принтеры, архивы и настройки не изменятся.', + enableHomeAssistant: 'Включить Home Assistant', + enableMqtt: 'Включить MQTT', + useTls: 'Использовать TLS', + enableMetricsEndpoint: 'Включить endpoint метрик', + availableMetrics: 'Доступные метрики', + editUser: 'Изменить пользователя', + deleteUserTitle: 'Удаление пользователя', + groupName: 'Название группы', + leaveEmptyForAnonymous: 'Оставьте пустым для анонимного доступа', + leaveEmptyForNoAuth: 'Оставьте пустым, чтобы не использовать аутентификацию', + enterNewPassword: 'Введите новый пароль', + confirmNewPassword: 'Повторите новый пароль', + enterGroupName: 'Введите название группы', + enterDescriptionOptional: 'Введите описание (необязательно)', + enterCurrentPassword: 'Введите текущий пароль', + enterNewPasswordMin6: 'Введите новый пароль (не менее 6 символов)', + toast: { + keyCopied: 'Ключ скопирован в буфер обмена', + copyFailed: 'Не удалось скопировать ключ', + keyAddedToBrowser: 'Ключ добавлен в обозреватель API', + clearLogsFailed: 'Не удалось очистить журнал', + uiPreferencesReset: 'Настройки интерфейса сброшены. Обновление страницы…', + authDisabled: 'Аутентификация отключена', + authDisableFailed: 'Не удалось отключить аутентификацию', + apiKeyCreated: 'Ключ API создан', + apiKeyDeleted: 'Ключ API удалён', + userCreated: 'Пользователь создан', + userUpdated: 'Пользователь обновлён', + userDeleted: 'Пользователь удалён', + groupCreated: 'Группа создана', + groupUpdated: 'Группа обновлена', + groupDeleted: 'Группа удалена', + fillRequiredFields: 'Заполните все обязательные поля', + passwordsDoNotMatch: 'Пароли не совпадают', + passwordTooShort: 'Пароль должен содержать не менее 8 символов', + passwordNeedsUppercase: 'Пароль должен содержать хотя бы одну заглавную букву', + passwordNeedsLowercase: 'Пароль должен содержать хотя бы одну строчную букву', + passwordNeedsDigit: 'Пароль должен содержать хотя бы одну цифру', + passwordNeedsSpecial: 'Пароль должен содержать хотя бы один специальный символ', + enterGroupName: 'Введите название группы', + settingsSaved: 'Настройки сохранены', + noPermissionUpdate: 'У вас нет прав на изменение настроек', + cameraSettingsSaved: 'Настройки камеры сохранены', + enterCameraUrl: 'Введите URL камеры', + passwordChanged: 'Пароль изменён', + connectionFailed: 'Не удалось подключиться', + testFailed: 'Проверка завершилась ошибкой', + cameraConnected: 'Камера подключена{{resolution}}', + }, + testConnection: 'Проверить подключение', + catalog: { + spoolCatalog: 'Каталог катушек', + spoolCatalogDescription: 'Масса пустых катушек по производителю и типу. Используется для автоматического определения массы при добавлении катушек.', + searchCatalog: 'Поиск по каталогу…', + addNewEntry: 'Добавить запись', + namePlaceholder: 'Название (например, Bambu Lab — пластик)', + weight: 'Масса', + type: 'Тип', + default: 'Стандартная', + custom: 'Пользовательская', + noMatch: 'Ничего не найдено', + empty: 'Каталог пуст', + deleteEntry: 'Удалить запись', + deleteConfirm: 'Удалить «{{name}}»?', + resetCatalog: 'Сбросить каталог', + resetConfirm: 'Сбросить каталог к исходному состоянию? Все пользовательские записи будут удалены.', + loadFailed: 'Не удалось загрузить каталог катушек', + nameWeightRequired: 'Укажите название и массу', + entryAdded: 'Запись добавлена', + addFailed: 'Не удалось добавить запись', + entryUpdated: 'Запись обновлена', + updateFailed: 'Не удалось обновить запись', + entryDeleted: 'Запись удалена', + deleteFailed: 'Не удалось удалить запись', + resetSuccess: 'Каталог сброшен к исходному состоянию', + resetFailed: 'Не удалось сбросить каталог', + exported: 'Экспортировано записей: {{count}}', + imported: 'Импортировано записей: {{added}}, пропущено: {{skipped}}', + importFailed: 'Не удалось импортировать: неверный формат JSON', + exportTooltip: 'Экспортировать каталог в JSON', + importTooltip: 'Импортировать каталог из JSON', + resetTooltip: 'Сбросить к исходному состоянию', + selectedCount: 'Выбрано: {{count}}', + deleteSelected: 'Удалить выбранные', + bulkDeleteConfirm: 'Удалить выбранные записи ({{count}})?', + bulkDeleted: 'Удалено записей: {{count}}', + bulkDeleteFailed: 'Не удалось удалить записи', + material: 'Материал', + spoolWeight: 'Масса катушки', + color: 'Цвет', + updateSpoolWeight: 'Обновить массу катушки', + filamentUpdated: 'Филамент обновлён', + filamentUpdateFailed: 'Не удалось обновить филамент', + filamentUpdateInvalid: 'Некорректные данные филамента', + keepExistingSpoolWeight: 'Сохранить прежнюю массу у существующих катушек', + keepExistingSpoolWeightDesc: 'Катушки, уже созданные с этим типом филамента, сохранят прежнюю массу тары. Для новых катушек будет использоваться обновлённое значение.', + applyToAllSpools: 'Применить ко всем катушкам', + applyToAllSpoolsDesc: 'Все расчёты массы для катушек этого типа немедленно начнут использовать новую массу тары.', + }, + colorCatalog: { + title: 'Каталог цветов', + description: 'Цвета филамента по производителю и материалу. Используются для автоматического определения цвета при добавлении катушек.', + searchColors: 'Поиск цветов…', + allManufacturers: 'Все производители', + addNewColor: 'Добавить цвет', + manufacturer: 'Производитель', + colorName: 'Название цвета', + hex: 'HEX', + materialOptional: 'Материал (необязательно)', + showing: 'Показано {{filtered}} из {{total}} цветов', + noMatch: 'Подходящие цвета не найдены', + empty: 'Каталог цветов пуст', + deleteColor: 'Удалить цвет', + deleteConfirm: 'Удалить «{{name}}»?', + resetCatalog: 'Сбросить каталог цветов', + resetConfirm: 'Сбросить каталог к исходному состоянию? Все пользовательские цвета будут удалены.', + sync: 'Синхронизировать', + starting: 'Запуск…', + syncTooltip: 'Синхронизировать с FilamentColors.xyz (более 2000 цветов; может занять около минуты)', + loadFailed: 'Не удалось загрузить каталог цветов', + fieldsRequired: 'Укажите производителя, название цвета и HEX-код', + colorAdded: 'Цвет добавлен', + addFailed: 'Не удалось добавить цвет', + colorUpdated: 'Цвет обновлён', + updateFailed: 'Не удалось обновить цвет', + colorDeleted: 'Цвет удалён', + deleteFailed: 'Не удалось удалить цвет', + resetSuccess: 'Каталог цветов сброшен к исходному состоянию', + resetFailed: 'Не удалось сбросить каталог цветов', + syncUpToDate: 'Каталог уже актуален (проверено цветов: {{count}})', + syncComplete: 'Добавлено новых цветов: {{added}}, уже существовало: {{skipped}}', + syncError: 'Ошибка синхронизации', + syncFailed: 'Не удалось синхронизировать каталог с FilamentColors.xyz', + exported: 'Экспортировано цветов: {{count}}', + imported: 'Импортировано цветов: {{added}}, пропущено: {{skipped}}', + importFailed: 'Не удалось импортировать: неверный формат JSON', + selectedCount: 'Выбрано: {{count}}', + deleteSelected: 'Удалить выбранные', + bulkDeleteConfirm: 'Удалить выбранные цвета ({{count}})?', + bulkDeleted: 'Удалено цветов: {{count}}', + bulkDeleteFailed: 'Не удалось удалить цвета', + }, + dateFormat: 'Формат даты', + dateFormatUs: 'США (ММ/ДД/ГГГГ)', + dateFormatEu: 'Европа (ДД/ММ/ГГГГ)', + dateFormatIso: 'ISO (ГГГГ-ММ-ДД)', + timeFormat: 'Формат времени', + timeFormat12: '12-часовой (3:30 PM)', + timeFormat24: '24-часовой (15:30)', + defaultPrinter: 'Принтер по умолчанию', + defaultPrinterDescription: 'Предварительно выбирать этот принтер при загрузке файлов, повторной печати и других операциях.', + slicerBambuStudio: 'Bambu Studio', + slicerOrcaSlicer: 'OrcaSlicer', + sidebarOrderDescription: 'Изменяйте порядок, видимость и пользовательские ссылки в настройках боковой панели.', + setDefault: 'Сделать стандартным', + sidebarOrderSetDefaultHint: 'Текущий порядок меню будет применяться к пользователям, которые ещё не настроили его самостоятельно.', + sidebarDefaultSet: 'Стандартный порядок меню сохранён.', + sidebarDefaultCleared: 'Стандартный порядок меню сброшен.', + sidebarDefaultFailed: 'Не удалось сохранить стандартный порядок меню.', + reset: 'Сбросить', + darkMode: 'Тёмная тема', + lightMode: 'Светлая тема', + active: '(активна)', + background: 'Фон', + accent: 'Акцент', + style: 'Стиль', + bgNeutral: 'Нейтральный', + bgWarm: 'Тёплый', + bgCool: 'Холодный', + bgOled: 'Чёрный OLED', + bgSlate: 'Сланцево-синий', + bgForest: 'Лесной зелёный', + accentGreen: 'Зелёный', + accentTeal: 'Бирюзовый', + accentBlue: 'Синий', + accentOrange: 'Оранжевый', + accentPurple: 'Фиолетовый', + accentRed: 'Красный', + styleClassic: 'Классический', + styleGlow: 'Свечение', + styleVibrant: 'Насыщенный', + themeToggleHint: 'Переключайте тёмную, светлую и системную тему значком в боковой панели.', + autoArchivePrints: 'Автоматически архивировать печать', + autoArchiveDescription: 'Автоматически сохранять 3MF после завершения печати', + saveThumbnailsDescription: 'Извлекать и сохранять изображения предпросмотра из 3MF', + captureFinishPhotoDescription: 'Сделать снимок камерой принтера после завершения печати. Во время печати Bambuddy записывает короткий таймлапс, чтобы получить кадр до опускания стола. Если таймлапс был включён для задания, файл сохранится; иначе после получения снимка он будет автоматически удалён.', + ffmpegNotInstalled: 'ffmpeg не установлен', + ffmpegRequired: 'Для захвата изображения требуется ffmpeg. Установите его командой brew install ffmpeg в macOS или apt install ffmpeg в Linux.', + camera: 'Камера', + cameraViewMode: 'Режим просмотра камеры', + cameraOverlayDescription: 'Камера открывается поверх основного экрана в окне с изменяемым размером', + cameraWindowDescription: 'Камера открывается в отдельном окне браузера', + externalCamerasDescription: 'Настройка внешних камер вместо встроенной камеры принтера. Поддерживаются потоки MJPEG, RTSP, HTTP-снимки и USB-камеры V4L2. Внешняя камера используется для просмотра в реальном времени и снимков после завершения печати.', + cameraPlaceholderUsb: 'Путь к устройству (/dev/video0)', + cameraPlaceholderUrl: 'URL камеры (rtsp://… или http://…)', + cameraTypeMjpeg: 'Поток MJPEG', + cameraTypeRtsp: 'Поток RTSP', + cameraTypeSnapshot: 'HTTP-снимок', + cameraTypeUsb: 'USB-камера (V4L2)', + cameraSnapshotUrl: 'URL снимка (необязательно)', + cameraSnapshotUrlPlaceholder: 'http://192.168.1.61:1984/api/frame.jpeg?src=printer', + cameraSnapshotUrlHelp: 'URL одиночного кадра для миниатюр уведомлений, снимков после печати, кадров послойного таймлапса и распознавания пластины. Для таймлапса и распознавания пластины должны быть отдельно включены соответствующие настройки принтера; этот URL задаёт лишь источник изображения. Оставьте пустым, чтобы получать кадры из указанного выше видеопотока. Полезно для go2rtc (/api/frame.jpeg) и IP-камер с отдельным endpoint снимка.', + cameraRotation: 'Поворот', + test: 'Проверить', + connected: 'Подключено', + disconnected: 'Отключено', + currency: 'Валюта', + defaultFilamentCost: 'Стоимость филамента по умолчанию (за кг)', + electricityCost: 'Стоимость электроэнергии за кВт·ч', + energyDisplayMode: 'Режим отображения энергии', + energyModePrintDescription: 'На панели показывается сумма энергии, израсходованной во время печати', + energyModeTotalDescription: 'На панели показывается полный расход энергии по данным умных розеток', + fileManager: 'Файловый менеджер', + createArchiveEntry: 'Создавать запись в архиве при печати', + createArchiveEntryDescription: 'При запуске печати из файлового менеджера при необходимости создавать запись в архиве', + lowDiskSpaceWarning: 'Предупреждение о нехватке места', + lowDiskSpaceDescription: 'Показывать предупреждение, когда свободного места остаётся меньше указанного порога', + printerFirmware: 'Прошивка принтера', + checkFirmwareDescription: 'Проверять наличие обновлений прошивки принтера у Bambu Lab', + bambuddySoftware: 'Программное обеспечение Bambuddy', + autoCheckDescription: 'Автоматически проверять наличие новых версий при запуске', + checkNow: 'Проверить сейчас', + updateAvailableVersion: 'Доступно обновление: v{{version}}', + releaseNotes: 'Примечания к выпуску', + updateViaDocker: 'Обновление через Docker Compose:', + updateViaHomeAssistant: 'Обновления устанавливаются через Home Assistant Supervisor. Чтобы установить новую версию, откройте в Home Assistant: Настройки → Дополнения → Bambuddy.', + updateViaWindowsInstaller: 'В Windows обновление выполняется повторным запуском установщика. Скачайте новую версию ниже — данные, настройки и принтеры сохранятся.', + downloadWindowsInstaller: 'Скачать установщик v{{version}}', + installUpdate: 'Установить обновление', + latestVersionRunning: 'Установлена последняя версия', + failedToCheckUpdates: 'Не удалось проверить обновления: {{error}}', + backupRestore: 'Резервное копирование и восстановление', + backupRestoreDescription: 'Экспорт и импорт настроек, а также резервное копирование в GitHub', + goToBackup: 'Перейти к резервным копиям', + externalUrl: 'Внешний URL', + externalUrlDescription: 'Внешний адрес, по которому доступен Bambuddy. Используется для изображений в уведомлениях и внешних интеграций.', + bambuddyUrl: 'URL Bambuddy', + externalUrlHint: 'Укажите протокол и порт, например http://192.168.1.100:8000', + ftpRetry: 'Повтор FTP-операций', + ftpRetryDescription: 'Повторять FTP-операции при нестабильном Wi‑Fi принтера. Применяется к скачиванию 3MF и таймлапсов, загрузке заданий и обновлению прошивки.', + autoRetryDescription: 'Автоматически повторять неудачные FTP-операции', + retryAttempts: 'Количество попыток', + retryDelay: 'Задержка между попытками', + connectionTimeout: 'Тайм-аут подключения', + time_one: '{{count}} раз', + time_other: '{{count}} раз', + second_one: '{{count}} секунда', + second_other: '{{count}} секунд', + nSeconds: '{{count}} секунд', + increaseForWeakWifi: 'Увеличьте для принтеров со слабым Wi‑Fi', + homeAssistant: 'Home Assistant', + homeAssistantFullDescription: 'Подключение к Home Assistant для управления умными розетками через REST API. Поддерживаются сущности switch, light, input_boolean и script.', + homeAssistantUrl: 'URL Home Assistant', + longLivedAccessToken: 'Долгосрочный токен доступа', + haTokenHint: 'Создайте токен в Home Assistant: Профиль → Долгосрочные токены доступа → Создать токен', + connectionSuccessful: 'Подключение установлено', + connectionFailed: 'Подключиться не удалось', + haConnectionSuccess: 'Подключение к Home Assistant установлено.', + haConnectionFailed: 'Не удалось подключиться к Home Assistant.', + mqttPublishing: 'Публикация MQTT', + mqttDescription: 'Публикация событий Bambuddy во внешнем MQTT-брокере для интеграции с Node-RED, Home Assistant и другими системами автоматизации.', + mqttEnableDescription: 'Публиковать события во внешнем MQTT-брокере', + brokerHostname: 'Имя хоста брокера', + port: 'Порт', + usernameOptional: 'Имя пользователя (необязательно)', + passwordOptional: 'Пароль (необязательно)', + topicPrefix: 'Префикс топиков', + topicPrefixHint: 'Топики будут иметь вид {{prefix}}/printers//status и т. п.', + prometheusMetrics: 'Метрики Prometheus', + prometheusEndpointDescription: 'Публиковать метрики принтеров по адресу /api/v1/metrics для мониторинга в Prometheus/Grafana.', + bearerTokenOptional: 'Bearer-токен (необязательно)', + bearerTokenHint: 'Если задан, запросы должны содержать Authorization: Bearer ', + metricsConnectionStatus: 'Состояние подключения', + metricsPrinterState: 'Состояние принтера (ожидание, печать и т. п.)', + metricsPrintProgress: 'Прогресс печати, 0–100 %', + metricsBedTemp: 'Температура стола', + metricsNozzleTemp: 'Температура сопла', + metricsPrintsTotal: 'Общее количество заданий по результату', + metricsMore: '…и другие данные: слои, вентиляторы, очередь, расход филамента', + smartPlugsDescription: 'Подключение умных розеток Tasmota или Home Assistant для автоматического управления питанием принтеров и учёта энергопотребления.', + allOn: 'Включить все', + allOff: 'Выключить все', + addSmartPlug: 'Добавить умную розетку', + energySummary: 'Сводка энергопотребления', + currentPower: 'Текущая мощность', + plugsOnline: 'Розеток в сети: {{reachable}}/{{total}}', + today: 'Сегодня', + yesterday: 'Вчера', + total: 'Всего', + enablePlugsForSummary: 'Включите розетки, чтобы увидеть сводку энергопотребления', + addNotificationProvider: 'Добавить', + systemBadge: '(системная)', + creating: 'Создание…', + changing: 'Изменение…', + deleteUserAndItems: 'Удалить пользователя И его объекты', + deleteUserKeepItems: 'Удалить пользователя, объекты оставить без владельца', + ok: 'ОК', + }, + notification: { + printStarted: { + title: 'Печать началась', + body: '{{printer}}: началась печать файла {{filename}}', + }, + printCompleted: { + title: 'Печать завершена', + body: '{{printer}}: файл {{filename}} успешно напечатан', + }, + printFailed: { + title: 'Ошибка печати', + body: '{{printer}}: печать файла {{filename}} завершилась ошибкой', + }, + printStopped: { + title: 'Печать остановлена', + body: '{{printer}}: печать файла {{filename}} остановлена', + }, + printProgress: { + title: 'Ход печати', + body: '{{printer}}: файл {{filename}} напечатан на {{percent}}%', + }, + printerOffline: { + title: 'Принтер не в сети', + body: '{{printer}} не в сети', + }, + printerError: { + title: 'Ошибка принтера', + body: '{{printer}}: {{error}}', + }, + filamentLow: { + title: 'Заканчивается филамент', + body: '{{printer}}: осталось мало филамента', + }, + maintenanceDue: { + title: 'Требуется обслуживание', + body: '{{printer}}: требуют внимания: {{items}}', + }, + }, + errors: { + generic: 'Что-то пошло не так', + networkError: 'Ошибка сети. Проверьте подключение.', + notFound: 'Не найдено', + unauthorized: 'Доступ не разрешён', + serverError: 'Ошибка сервера', + validationError: 'Проверьте введённые данные', + printerConnectionFailed: 'Не удалось подключиться к принтеру', + saveFailed: 'Не удалось сохранить изменения', + deleteFailed: 'Не удалось удалить', + loadFailed: 'Не удалось загрузить данные', + }, + hmsErrors: { + title: 'Ошибки — {{name}}', + noErrors: 'Ошибок нет', + viewOnWiki: 'Открыть в Bambu Lab Wiki', + unknownCode: 'Неизвестный код HMS — подробности см. в Bambu Lab Wiki.', + clearInstructions: 'Устраните ошибки на принтере, чтобы они исчезли из этого списка.', + clearErrors: 'Очистить ошибки', + clearSuccess: 'Ошибки HMS очищены', + clearFailed: 'Не удалось очистить ошибки HMS', + actionSuccess: 'Команда отправлена принтеру', + actionFailed: 'Не удалось отправить команду', + actions: { + RESUME_PRINTING: 'Продолжить печать', + RESUME_PRINTING_DEFECTS: 'Продолжить (дефекты допустимы)', + RESUME_PRINTING_PROBELM_SOLVED: 'Продолжить (проблема устранена)', + STOP_PRINTING: 'Остановить печать', + CHECK_ASSISTANT: 'Проверить помощник', + FILAMENT_EXTRUDED: 'Филамент выдавливается — продолжить', + RETRY_FILAMENT_EXTRUDED: 'Филамент ещё не выходит — повторить', + CONTINUE: 'Готово — продолжить', + LOAD_VIRTUAL_TRAY: 'Загрузить филамент', + OK_BUTTON: 'ОК', + FILAMENT_LOAD_RESUME: 'Филамент загружен — продолжить', + JUMP_TO_LIVEVIEW: 'Открыть камеру', + NO_REMINDER_NEXT_TIME: 'Больше не напоминать', + REFRESH_NOZZLE: 'Проверить ещё раз', + IGNORE_NO_REMINDER_NEXT_TIME: 'Игнорировать и больше не напоминать', + IGNORE_RESUME: 'Игнорировать и продолжить', + PROBLEM_SOLVED_RESUME: 'Проблема устранена — продолжить', + TURN_OFF_FIRE_ALARM: 'Понятно, отключить пожарную тревогу', + RETRY_PROBLEM_SOLVED: 'Повторить (проблема устранена)', + CANCLE: 'Отмена', + STOP_DRYING: 'Остановить сушку', + PROCEED: 'Продолжить', + OK_JUMP_RACK: 'ОК', + ABORT: 'Прервать', + DISABLE_PURIFICATION: 'Отключить очистку воздуха для этой печати', + DONT_REMIND_NEXT_TIME: 'Больше не напоминать', + DBL_CHECK_CANCEL: 'Отмена', + DBL_CHECK_DONE: 'Готово', + DBL_CHECK_RETRY: 'Повторить', + DBL_CHECK_RESUME: 'Продолжить', + DBL_CHECK_OK: 'Подтвердить', + REMOVE_CLOSE_BTN: 'Закрыть', + }, + }, + mqttDebug: { + title: 'Журнал отладки MQTT', + searchPlaceholder: 'Поиск по теме или содержимому...', + noMessages: 'Сообщений пока нет', + startLoggingHint: 'Нажмите «Начать запись», чтобы перехватывать сообщения MQTT', + noMessagesMatch: 'Нет сообщений, соответствующих фильтру', + adjustFilterHint: 'Измените запрос или параметры фильтра', + incoming: 'Входящие', + outgoing: 'Исходящие', + loggingStopped: 'Запись остановлена', + loggingActive: 'Запись активна — сообщения обновляются автоматически', + startLogging: 'Начать запись', + stopLogging: 'Остановить запись', + clearLog: 'Очистить журнал', + topic: 'Тема', + timestamp: 'Время', + direction: 'Направление', + all: 'Все', + }, + printerFiles: { + title: 'Файлы принтера', + storageUsed: 'Занято:', + storageFree: 'Свободно:', + filterPlaceholder: 'Фильтр файлов...', + deleteButton: 'Удалить', + deleteFiles: 'Удалить файлы: {{count}}', + deleteFileConfirm: 'Удалить «{{name}}»? Это действие нельзя отменить.', + deleteFilesConfirm: 'Удалить выбранные файлы ({{count}})? Это действие нельзя отменить.', + noFiles: 'На принтере нет файлов', + loadingFiles: 'Загрузка файлов...', + failedToLoad: 'Не удалось загрузить файлы', + toast: { + filesDeleted: 'Удалено файлов: {{count}}', + deleteFailed: 'Не удалось удалить: {{error}}', + }, + }, + confirm: { + delete: 'Удалить этот объект?', + unsavedChanges: 'Есть несохранённые изменения. Всё равно уйти со страницы?', + clearQueue: 'Очистить очередь печати?', + }, + changePassword: { + title: 'Изменение пароля', + currentPassword: 'Текущий пароль', + currentPasswordPlaceholder: 'Введите текущий пароль', + newPassword: 'Новый пароль', + newPasswordPlaceholder: 'Введите новый пароль (не менее 6 символов)', + confirmPassword: 'Подтвердите новый пароль', + confirmPasswordPlaceholder: 'Повторите новый пароль', + passwordsDoNotMatch: 'Пароли не совпадают', + passwordTooShort: 'Пароль должен содержать не менее 6 символов', + changing: 'Изменение...', + success: 'Пароль изменён', + failed: 'Не удалось изменить пароль', + }, + plateAlert: { + title: 'Печать приостановлена!', + message: 'На печатной пластине обнаружены объекты. Печать автоматически приостановлена. Очистите пластину и продолжите печать.', + understand: 'Понятно', + }, + camera: { + title: 'Камера', + invalidPrinterId: 'Неверный идентификатор принтера', + live: 'Прямой эфир', + snapshot: 'Снимок', + restartStream: 'Перезапустить поток', + refreshSnapshot: 'Обновить снимок', + fullscreen: 'На весь экран', + exitFullscreen: 'Выйти из полноэкранного режима', + connectingToCamera: 'Подключение к камере...', + capturingSnapshot: 'Создание снимка...', + connectionLost: 'Соединение потеряно', + connectionFailed: 'Не удалось подключиться к камере', + reconnecting: 'Повторное подключение через {{countdown}} с... (попытка {{attempt}} из {{max}})', + reconnectNow: 'Подключиться сейчас', + cameraUnavailable: 'Камера недоступна', + cameraUnavailableDesc: 'Убедитесь, что принтер включён и подключён к сети.', + noCamera: 'Камера отсутствует', + retry: 'Повторить', + cameraStream: 'Видеопоток камеры', + zoomOut: 'Уменьшить', + zoomIn: 'Увеличить', + resetZoom: 'Сбросить масштаб', + recording: 'Запись', + startRecording: 'Начать запись', + stopRecording: 'Остановить запись', + chamberLight: 'Переключить освещение камеры принтера', + unavailable: 'Камера недоступна', + diagnose: { + button: 'Диагностика', + modalTitle: 'Диагностика камеры', + running: 'Выполняется диагностика...', + runFailed: 'Не удалось выполнить диагностику: {{error}}', + retry: 'Запустить снова', + stage: { + tcp_reachable: 'Доступность по сети', + first_frame: 'Получение кадра', + live_stream_active: 'Активный видеопоток', + }, + summary: { + all_ok: 'Камера работает. Все этапы диагностики завершены успешно.', + live_stream_active_healthy: 'Камера уже передаёт свежие кадры — дополнительная проверка не требуется.', + printer_unreachable: 'Принтер недоступен. Проверьте IP-адрес, сетевое подключение и питание принтера.', + camera_port_closed: 'Принтер доступен, но порт камеры закрыт. Убедитесь, что в настройках принтера включены режим «Только LAN» и режим разработчика.', + no_frame: 'Подключение к камере установлено, но кадры не поступают. Повторите попытку или проверьте, включена ли камера в настройках принтера.', + unknown_failure: 'Диагностика камеры завершилась неизвестной ошибкой. Подробности см. в журнале поддержки.', + }, + meta: { + protocol: 'Протокол', + port: 'Порт', + profile: 'Профиль', + }, + }, + }, + groups: { + title: 'Управление группами', + subtitle: 'Настройка групп разрешений для контроля доступа', + backToSettings: 'Вернуться к настройкам', + createGroup: 'Создать группу', + noPermission: 'У вас нет доступа к этой странице.', + system: 'Системная', + noDescription: 'Без описания', + usersCount: 'Пользователей: {{count}}', + permissionsCount: 'Разрешений: {{count}}', + edit: 'Изменить', + delete: 'Удалить', + toast: { + created: 'Группа создана', + updated: 'Группа обновлена', + deleted: 'Группа удалена', + enterGroupName: 'Введите название группы', + }, + modal: { + editGroup: 'Изменение группы', + createGroup: 'Создание группы', + cancel: 'Отмена', + saving: 'Сохранение...', + creating: 'Создание...', + saveChanges: 'Сохранить изменения', + }, + form: { + groupName: 'Название группы', + groupNamePlaceholder: 'Введите название группы', + systemGroupWarning: 'Названия системных групп изменить нельзя', + description: 'Описание', + descriptionPlaceholder: 'Введите описание (необязательно)', + permissions: 'Разрешения (выбрано: {{count}})', + }, + deleteModal: { + title: 'Удаление группы', + message: 'Удалить эту группу? Входящие в неё пользователи потеряют соответствующие разрешения.', + confirm: 'Удалить группу', + }, + editor: { + title: 'Изменение группы', + createTitle: 'Создание группы', + search: 'Поиск разрешений...', + selectAll: 'Выбрать все', + clearAll: 'Очистить выбор', + permissionsSelected: 'Выбрано: {{count}}', + noResults: 'Нет разрешений, соответствующих запросу', + websocketHint: 'Необходимо для обновлений в реальном времени. Без этого интерфейс будет периодически опрашивать сервер.', + }, + }, + users: { + title: 'Управление пользователями', + subtitle: 'Управление пользователями и их доступом к Bambuddy', + backToSettings: 'Вернуться к настройкам', + createUser: 'Создать пользователя', + noPermission: 'У вас нет доступа к этой странице.', + admin: 'Администратор', + noGroups: 'Без групп', + active: 'Активен', + inactive: 'Отключён', + edit: 'Изменить', + delete: 'Удалить', + system: 'Системный', + noGroupsAvailable: 'Нет доступных групп', + table: { + username: 'Имя пользователя', + groups: 'Группы', + status: 'Состояние', + actions: 'Действия', + }, + toast: { + created: 'Пользователь создан', + updated: 'Пользователь обновлён', + deleted: 'Пользователь удалён', + fillRequired: 'Заполните все обязательные поля', + passwordsDoNotMatch: 'Пароли не совпадают', + passwordTooShort: 'Пароль должен содержать не менее 6 символов', + ldapProvisioned: 'Пользователь LDAP «{{username}}» добавлен', + }, + modal: { + createUser: 'Создание пользователя', + editUser: 'Изменение пользователя', + cancel: 'Отмена', + creating: 'Создание...', + saving: 'Сохранение...', + saveChanges: 'Сохранить изменения', + advancedAuthSubtitle: 'с расширенной аутентификацией', + tabsAriaLabel: 'Источник пользователя', + localTab: 'Локальный', + ldapTab: 'LDAP', + ldapSearchLabel: 'Поиск в каталоге', + ldapSearchPlaceholder: 'Введите имя пользователя, имя или email...', + ldapMinChars: 'Для поиска введите не менее 2 символов', + ldapTypeToSearch: 'Начните вводить запрос для поиска в каталоге LDAP', + ldapSearching: 'Поиск в каталоге...', + ldapNoResults: 'В каталоге нет подходящих пользователей', + ldapSearchError: 'Ошибка поиска в каталоге. Проверьте состояние сервера LDAP.', + ldapAlreadyProvisioned: 'Уже добавлен', + ldapSelectedLabel: 'Выбран', + ldapProvision: 'Добавить пользователя', + ldapProvisioning: 'Добавление...', + ldapErrorProvision: 'Не удалось добавить пользователя. Проверьте сервер LDAP и повторите попытку.', + }, + form: { + username: 'Имя пользователя', + usernamePlaceholder: 'Введите имя пользователя', + email: 'Email', + emailPlaceholder: 'user@example.com', + password: 'Пароль', + passwordPlaceholder: 'Введите пароль', + confirmPassword: 'Подтверждение пароля', + confirmPasswordPlaceholder: 'Повторите пароль', + newPasswordPlaceholder: 'Введите новый пароль', + confirmNewPasswordPlaceholder: 'Повторите новый пароль', + leaveBlankToKeep: 'оставьте пустым, чтобы сохранить текущий', + groups: 'Группы', + optional: 'необязательно', + autoGeneratedPassword: 'Надёжный пароль будет создан автоматически и отправлен пользователю по email.', + passwordManagedByAdvancedAuth: 'Пароль управляется расширенной аутентификацией. Используйте «Сбросить пароль», чтобы отправить пользователю новый пароль по email.', + resetPassword: 'Сбросить пароль', + resettingPassword: 'Сброс пароля...', + }, + deleteModal: { + title: 'Удаление пользователя', + message: 'Удалить этого пользователя? Это действие нельзя отменить.', + confirm: 'Удалить пользователя', + }, + }, + streamOverlay: { + title: 'Оформление трансляции', + invalidPrinterId: 'Неверный идентификатор принтера', + cameraStream: 'Видеопоток камеры', + progress: 'Прогресс', + eta: 'Осталось', + printerIdle: 'Принтер простаивает', + printerOffline: 'Принтер не в сети', + status: { + printing: 'Печать', + paused: 'Приостановлено', + finished: 'Завершено', + failed: 'Ошибка', + idle: 'Ожидание', + unknown: 'Неизвестно', + }, + }, + profiles: { + title: 'Профили', + subtitle: 'Управление профилями слайсера и калибровками Pressure Advance', + tabs: { + bambuCloud: 'Bambu Cloud', + orcaCloud: 'Orca Cloud', + local: 'Локальные профили', + kprofiles: 'K-профили', + }, + orcaCloud: { + connectedAs: 'Подключено как', + logout: 'Отключиться', + noLogoutPermission: 'У вас нет разрешения отключаться от Orca Cloud', + noConnectPermission: 'У вас нет разрешения подключаться к Orca Cloud', + retry: 'Повторить', + back: 'Использовать другой способ входа', + connect: { + title: 'Подключение к Orca Cloud', + description: 'Войдите в Orca Cloud, чтобы синхронизировать профили слайсера с Bambuddy.', + }, + providers: { + google: 'Войти через Google', + apple: 'Войти через Apple', + github: 'Войти через GitHub', + email: 'Войти по email и паролю', + }, + password: { + title: 'Вход по email и паролю', + email: 'Email', + emailPlaceholder: 'you@example.com', + password: 'Пароль', + submit: 'Войти', + }, + paste: { + title: 'Завершение входа', + step1: 'В новой вкладке открылась страница входа Orca Cloud. Войдите в свою учётную запись Orca.', + step2: 'Браузер перенаправит вас на адрес localhost, который не откроется. Это нормально — нам нужен сам адрес.', + step3: 'Скопируйте весь адрес из адресной строки браузера и вставьте его ниже.', + signInUrl: 'Если вкладка входа не открылась, нажмите эту ссылку:', + label: 'Вставьте сюда URL обратного вызова', + placeholder: 'http://localhost:41172/callback?code=...&state=...', + submit: 'Завершить подключение', + }, + profiles: { + title: 'Ваши профили Orca Cloud ({{count}})', + refresh: 'Обновить', + empty: 'В вашей учётной записи Orca Cloud пока нет профилей.', + }, + toast: { + connected: 'Подключено к Orca Cloud как {{email}}', + disconnected: 'Orca Cloud отключён', + }, + errors: { + startFailed: 'Не удалось начать вход в Orca Cloud.', + finishFailed: 'Не удалось завершить вход в Orca Cloud.', + passwordFailed: 'Не удалось войти с указанными email и паролем.', + passwordEmpty: 'Введите email и пароль.', + emptyPaste: 'Вставьте URL обратного вызова из браузера.', + noCode: 'Этот адрес не похож на URL обратного вызова Orca Cloud: отсутствует параметр code. Скопируйте полный адрес из адресной строки.', + }, + }, + localProfiles: { + title: 'Локальные профили', + subtitle: 'Импорт профилей OrcaSlicer и управление ими', + import: 'Импортировать профили', + importDesc: 'Перетащите сюда файлы .bbscfg, .bbsflmt, .orca_filament, .zip или .json', + importing: 'Импорт...', + search: 'Поиск локальных профилей...', + noPresets: 'Локальных профилей пока нет', + noSearchResults: 'Нет профилей, соответствующих запросу', + badge: 'Локальный', + edit: 'Изменить', + delete: 'Удалить', + cancel: 'Отмена', + deleteConfirmTitle: 'Удаление профиля', + deleteConfirm: 'Удалить этот профиль? Это действие нельзя отменить.', + source: 'Источник', + inheritsFrom: 'Наследует', + filamentType: 'Тип', + vendor: 'Производитель', + compatiblePrinters: 'Принтеры', + nozzleTemp: 'Температура сопла', + cost: 'Стоимость', + density: 'Плотность', + pressureAdvance: 'Pressure Advance', + filament: 'Филамент', + process: 'Процесс', + printer: 'Принтер', + toast: { + importSuccess: 'Импортировано профилей: {{count}}', + importSkipped: 'Пропущено дубликатов: {{count}}', + importError: 'Ошибок при импорте: {{count}}', + deleted: 'Профиль удалён', + updated: 'Профиль обновлён', + }, + }, + connectedAs: 'Подключено как', + logout: 'Выйти', + noLogoutPermission: 'У вас нет разрешения выходить из учётной записи', + failedToLoad: 'Не удалось загрузить профили', + retry: 'Повторить', + time: { + justNow: 'Только что', + minsAgo: '{{count}} мин назад', + hoursAgo: '{{count}} ч назад', + daysAgo: '{{count}} дн назад', + }, + toast: { + loggedOut: 'Вы вышли из учётной записи', + }, + login: { + title: 'Подключение к Bambu Cloud', + subtitle: 'Синхронизация профилей слайсера между устройствами', + email: 'Email', + password: 'Пароль', + region: 'Регион', + regionGlobal: 'Глобальный', + regionChina: 'Китай', + verificationCode: 'Код подтверждения', + totpCode: 'Код приложения-аутентификатора', + checkEmail: 'Проверьте почту {{email}}: туда отправлен шестизначный код', + enterTotpHint: 'Введите шестизначный код из приложения-аутентификатора', + accessToken: 'Токен доступа', + accessTokenHint: 'Вставьте токен доступа Bambu Cloud. Для учётных записей китайского региона, привязанных к телефону, доступен только этот способ: вход по email не поддерживается. Инструкцию по получению токена из cookie MakerWorld см. в wiki.', + back: 'Назад', + loginButton: 'Войти', + verifyButton: 'Подтвердить', + setTokenButton: 'Сохранить токен', + useToken: 'Использовать токен доступа', + useEmail: 'Войти по email', + toast: { + loggedIn: 'Вход выполнен', + codeSent: 'Код подтверждения отправлен по email', + enterTotp: 'Введите код из приложения-аутентификатора', + tokenSet: 'Токен сохранён', + }, + }, + presets: { + myPreset: 'Мой профиль (редактируемый)', + duplicate: 'Создать копию', + editable: 'Редактируемый', + failedToLoadDetails: 'Не удалось загрузить сведения о профиле', + deleteConfirm: 'Удалить этот профиль?', + deleteWarning: 'Профиль «{{name}}» будет безвозвратно удалён из Bambu Cloud. Это действие нельзя отменить.', + noDuplicatePermission: 'У вас нет разрешения копировать профили', + noEditPermission: 'У вас нет разрешения редактировать профили', + noDeletePermission: 'У вас нет разрешения удалять профили', + types: { + filament: 'Профиль филамента', + printer: 'Профиль принтера', + process: 'Профиль процесса', + }, + toast: { + deleted: 'Профиль удалён', + created: 'Профиль создан', + updated: 'Профиль обновлён', + duplicated: 'Копия профиля создана', + fieldAdded: 'Добавлено поле «{{key}}»', + exported: 'Профиль экспортирован', + }, + baseLabel: 'Базовый: {{name}}', + currentLabel: 'Текущий: {{name}}', + newPreset: 'Новый профиль', + editPreset: 'Изменение профиля', + duplicatePreset: 'Копирование профиля', + createNewPreset: 'Создание профиля', + customizeSettings: 'Настройте параметры нового профиля', + compareWithBase: 'Сравнить с базовым профилем', + compare: 'Сравнить', + basePreset: 'Базовый профиль', + selectBasePreset: 'Выберите базовый профиль...', + presetName: 'Название профиля', + myCustomPreset: 'Мой профиль', + inheritsFrom: 'Наследует от', + dropJsonToImport: 'Перетащите JSON для импорта', + tabs: { + common: 'Основные', + allFields: 'Все поля', + }, + availableFields: 'Доступные поля', + searchFieldsPlaceholder: 'Поиск полей...', + noMatchingFields: 'Нет подходящих полей', + allFieldsAdded: 'Все поля добавлены', + addCustomField: 'Добавить произвольное поле', + yourOverrides: 'Ваши переопределения', + noOverridesYet: 'Переопределений пока нет', + clickFieldsToAdd: 'Нажимайте поля слева, чтобы добавить их', + saveAsTemplate: 'Сохранить как шаблон', + jsonTip: 'Совет: перетащите файл .json в это окно, чтобы импортировать настройки', + }, + cloudView: { + searchPlaceholder: 'Поиск профилей...', + templates: 'Шаблоны', + refresh: 'Обновить', + newPreset: 'Новый профиль', + clearFilters: 'Сбросить фильтры', + compareMode: 'Режим сравнения', + selectAnotherPreset: 'Выберите другой профиль типа «{{type}}»', + clickTwoPresets: 'Выберите два профиля одного типа для сравнения', + selectFirst: '1. Выберите первый', + selectSecond: '2. Выберите второй', + compareNow: 'Сравнить', + lastSynced: 'Последняя синхронизация:', + showingCount: 'Показано {{showing}} из {{total}} профилей', + noPresetsFound: 'Профили не найдены', + columns: { + filament: 'Филамент', + process: 'Процесс', + printer: 'Принтер', + }, + noFilamentPresets: 'Нет профилей филамента', + noProcessPresets: 'Нет профилей процесса', + noPrinterPresets: 'Нет профилей принтера', + filters: { + type: 'Тип', + owner: 'Владелец', + printer: 'Принтер', + nozzle: 'Сопло', + filament: 'Филамент', + layer: 'Слой', + all: 'Все', + myPresets: 'Мои профили', + builtIn: 'Встроенные', + process: 'Процесс', + }, + noTemplatesPermission: 'У вас нет разрешения управлять шаблонами', + noRefreshPermission: 'У вас нет разрешения обновлять профили', + noCreatePermission: 'У вас нет разрешения создавать профили', + }, + templates: { + title: 'Быстрые шаблоны', + noTemplates: 'Шаблонов пока нет', + createFirst: 'Создавайте шаблоны в редакторе профилей', + typeFilter: 'Тип:', + deleteTitle: 'Удаление шаблона', + deleteWarning: 'Это действие нельзя отменить', + deleteConfirm: 'Удалить шаблон «{{name}}»?', + namePlaceholder: 'Название шаблона', + descriptionPlaceholder: 'Описание', + settingsJson: 'Настройки (JSON)', + fieldsCount: 'Полей: {{count}}', + shownInModals: 'Показывается в окнах', + hiddenInModals: 'Скрыт в окнах', + apply: 'Применить', + toast: { + deleted: 'Шаблон удалён', + updated: 'Шаблон обновлён', + created: 'Шаблон создан', + applied: 'Шаблон применён', + }, + }, + }, + support: { + debugLoggingActive: 'Отладочное журналирование включено', + manageLogs: 'Управление', + collectItem7: 'Подключение принтеров и версии прошивок', + collectItem8: 'Состояние интеграций (Spoolman, MQTT, HA)', + collectItem9: 'Сетевые интерфейсы (только подсети)', + collectItem10: 'Версии пакетов Python', + collectItem11: 'Проверка состояния базы данных', + collectItem12: 'Сведения о среде Docker', + bundleGenerating: 'Формирование пакета...', + bundleStepConnection: 'Проверка подключения принтеров', + bundleStepVirtualPrinters: 'Проверка настройки виртуальных принтеров', + bundleStepLogScan: 'Поиск известных проблем в последних журналах', + bundleStepBuild: 'Создание ZIP-пакета для поддержки', + }, + login: { + title: 'Вход в Bambuddy', + subtitle: 'Войдите в свою учётную запись', + username: 'Имя пользователя', + usernamePlaceholder: 'Введите имя пользователя', + usernameOrEmail: 'Имя пользователя или email', + usernameOrEmailPlaceholder: 'Имя пользователя или email', + password: 'Пароль', + passwordPlaceholder: 'Введите пароль', + signIn: 'Войти', + signingIn: 'Вход...', + rememberMe: 'Запомнить меня', + forgotPassword: 'Забыли пароль?', + autologinFailed: 'Автоматический вход через SSO не выполнен. Выберите провайдера ниже.', + localDisabledNotice: 'Локальный вход отключён. Используйте одного из SSO-провайдеров ниже.', + loginSuccess: 'Вход выполнен', + loginFailed: 'Не удалось войти', + enterCredentials: 'Введите имя пользователя и пароль', + enterEmail: 'Введите адрес электронной почты', + oidcLoginFailed: 'Ошибка входа через OIDC', + oidcErrors: { + providerError: 'Провайдер удостоверений вернул ошибку', + missingParameters: 'В ответе OIDC отсутствуют обязательные параметры', + invalidState: 'Состояние OIDC недействительно или уже использовано', + stateExpired: 'Сеанс входа OIDC истёк — повторите попытку', + providerNotFound: 'Провайдер OIDC не найден', + discoveryFailed: 'Не удалось получить документ обнаружения OIDC', + invalidDiscovery: 'Документ обнаружения OIDC недействителен', + networkError: 'Сетевая ошибка при обмене токена OIDC', + badResponse: 'Неожиданный ответ при обмене токена OIDC', + noIdToken: 'Провайдер OIDC не вернул ID-токен', + validationFailed: 'Не удалось проверить токен OIDC', + nonceMismatch: 'Несовпадение nonce OIDC — возможна атака повторного воспроизведения', + missingSubClaim: 'В токене OIDC отсутствует поле sub', + noLinkedAccount: 'С этой учётной записью OIDC не связана локальная учётная запись', + accountInactive: 'Учётная запись неактивна', + userResolutionFailed: 'Не удалось определить учётную запись', + internalError: 'Внутренняя ошибка при входе через OIDC', + tokenExchangeFailed: 'Не удалось обменять токен OIDC', + }, + forgotPasswordTitle: 'Восстановление пароля', + forgotPasswordMessage: 'Обратитесь к системному администратору для сброса пароля.', + forgotPasswordEmailMessage: 'Введите адрес электронной почты, и мы отправим новый пароль.', + emailAddress: 'Адрес электронной почты', + emailPlaceholder: 'your.email@example.com', + cancel: 'Отмена', + sending: 'Отправка...', + sendResetEmail: 'Отправить письмо для сброса', + howToReset: 'Как сбросить пароль:', + resetStep1: 'Свяжитесь с администратором Bambuddy', + resetStep2: 'Попросите сбросить пароль в разделе управления пользователями', + resetStep3: 'Администратор задаст новый временный пароль', + resetStep4: 'Войдите с новым паролем и измените его в настройках', + gotIt: 'Понятно', + resetPassword: { + title: 'Новый пароль', + subtitle: 'Введите и подтвердите новый пароль.', + newPassword: 'Новый пароль', + newPasswordPlaceholder: 'Не менее 8 символов', + confirmPassword: 'Подтверждение пароля', + confirmPasswordPlaceholder: 'Повторите новый пароль', + saving: 'Сохранение…', + submit: 'Установить новый пароль', + backToLogin: 'Вернуться ко входу', + passwordsDoNotMatch: 'Пароли не совпадают', + passwordTooShort: 'Пароль должен содержать не менее 8 символов', + resetFailed: 'Не удалось сбросить пароль. Возможно, ссылка устарела.', + }, + twoFA: { + title: 'Двухфакторная аутентификация', + subtitle: 'Учётная запись защищена 2FA. Введите код подтверждения.', + methodAuthenticator: 'Приложение-аутентификатор', + methodEmail: 'Код по email', + methodBackup: 'Резервный код', + instructionsTotp: 'Откройте приложение-аутентификатор и введите шестизначный код Bambuddy.', + instructionsEmail: 'Шестизначный код отправлен на вашу электронную почту. Он действует 10 минут.', + instructionsEmailNotSent: 'Нажмите кнопку ниже, чтобы получить код подтверждения по email.', + instructionsBackup: 'Введите один из восьмизначных резервных кодов восстановления. Каждый код используется только один раз.', + sendCodeButton: 'Отправить код по email', + sendingCode: 'Отправка...', + resendCode: 'Отправить код повторно', + codeLabel: 'Код подтверждения', + backupCodeLabel: 'Резервный код', + codePlaceholder: '000000', + backupCodePlaceholder: 'XXXXXXXX', + verifyButton: 'Подтвердить', + verifyingButton: 'Проверка...', + backToLogin: '← Вернуться ко входу', + orContinueWith: 'или продолжить через', + signInWith: 'Войти через {{provider}}', + enterCode: 'Введите код подтверждения', + sendCodeFailed: 'Не удалось отправить код подтверждения', + invalidCode: 'Неверный код. Повторите попытку.', + }, + }, + fileManager: { + title: 'Файловый менеджер', + subtitle: 'Организация и управление файлами для печати', + uploadFiles: 'Загрузить файлы', + newFolder: 'Новая папка', + folderName: 'Имя папки', + folderNamePlaceholder: 'например, Функциональные детали', + renameFile: 'Переименовать файл', + renameFolder: 'Переименовать папку', + invalidFilenameChar: 'Символ «{{char}}» нельзя использовать в именах файлов печати. SD-карта принтера не принимает: < > : " / \\ | ? *', + moveFiles: 'Переместить файлы ({{count}})', + rootNoFolder: 'Корень (без папки)', + current: 'текущая', + linkFolder: 'Связать папку', + linkFolderDescription: 'Связать «{{name}}» с проектом или архивом для быстрого доступа.', + project: 'Проект', + archive: 'Архив', + noProjectsFound: 'Проекты не найдены', + noArchivesFound: 'Архивы не найдены', + unlink: 'Отвязать', + link: 'Связать', + dragDropFiles: 'Перетащите файлы сюда', + dropFilesHere: 'Перетащите файлы сюда', + releaseToUpload: 'Отпустите для загрузки', + orClickToBrowse: 'или нажмите для выбора', + allFileTypesSupported: 'Поддерживаются все типы файлов. ZIP-архивы будут распакованы.', + zipFilesDetected: 'Обнаружены ZIP-архивы', + zipExtractOptions: 'ZIP-архивы будут распакованы. Выберите способ обработки структуры папок:', + preserveZipStructure: 'Сохранить структуру папок из ZIP', + createFolderFromZip: 'Создать папку с именем ZIP-файла', + stlThumbnailGeneration: 'Создание миниатюр STL', + zipMayContainStl: 'ZIP-архивы могут содержать STL-файлы. Миниатюры можно создать при распаковке.', + thumbnailsCanBeGenerated: 'Для STL-файлов можно создать миниатюры. Обработка крупных моделей может занять больше времени.', + generateThumbnailsForStl: 'Создать миниатюры для STL-файлов', + threemfDetected: 'Обнаружены файлы 3MF', + threemfExtractionInfo: 'Модель принтера, материал, цвет и параметры печати будут автоматически извлечены из файлов 3MF.', + willBeExtracted: 'Будут извлечены', + filesExtracted: 'Извлечено файлов: {{count}}', + uploadComplete: 'Загрузка завершена: успешно — {{succeeded}}', + uploadFailed: 'Ошибка загрузки', + zipFilesFailed: 'Не удалось обработать файлов: {{count}}', + uploading: 'Загрузка...', + changeLink: 'Изменить связь...', + linkTo: 'Связать с...', + linkToProjectOrArchive: 'Связать с проектом или архивом', + generateThumbnail: 'Создать миниатюру', + generateThumbnails: 'Создать миниатюры', + generateThumbnailsForMissing: 'Создать отсутствующие миниатюры для STL-файлов', + gridView: 'Плитка', + listView: 'Список', + lowDiskSpaceWarning: 'Мало свободного места', + lowDiskSpaceDetails: 'Свободно только {{free}} из {{total}}. Порог предупреждения в настройках: {{threshold}} ГБ.', + files: 'Файлы', + folders: 'Папки', + size: 'Размер', + free: 'Свободно', + allFiles: 'Все файлы', + allExternal: 'Внешние', + externalIsEmpty: 'Внешних файлов нет', + externalEmptyDescription: 'Здесь появятся файлы из подключённых внешних папок.', + wrap: 'Перенос строк', + enableTextWrapping: 'Включить перенос строк', + disableTextWrapping: 'Отключить перенос строк', + collapse: 'Свернуть', + collapseFoldersByDefault: 'Сворачивать папки по умолчанию', + expandFoldersByDefault: 'Разворачивать папки по умолчанию', + folderSort: 'Сортировка папок', + folderSortByName: 'По имени', + folderSortByActivity: 'По последней активности', + dragToResizeTooltip: 'Перетащите для изменения размера, двойной щелчок — сброс', + searchFiles: 'Поиск файлов...', + searchSubfoldersHint: 'С учётом вложенных папок', + readme: { + truncated: 'Показано не полностью', + }, + tags: { + title: 'Метки', + subtitle: 'Помечайте файлы для сквозной фильтрации: игрушки, безопасно для детей, только PETG и что угодно ещё.', + manage: 'Метки', + manageTitle: 'Управление каталогом меток', + add: 'Новая метка', + edit: 'Переименовать метку', + name: 'Название', + fileCount: 'Файлы', + empty: 'Меток пока нет. Создайте первую, чтобы начать помечать файлы.', + noMatches: 'Подходящие метки не найдены.', + createPlaceholder: 'например, игрушки, детям, petg', + createButton: 'Создать', + nameRequired: 'Укажите название.', + searchPlaceholder: 'Фильтр меток...', + created: 'Метка создана.', + updated: 'Метка переименована.', + deleted: 'Метка удалена.', + saveFailed: 'Не удалось сохранить метку.', + deleteFailed: 'Не удалось удалить метку.', + applyFailed: 'Не удалось применить метки.', + applyAdd: 'Добавить метки', + applyRemove: 'Удалить метки', + applyAddSuccess: 'Добавлено меток: {{count}}; обработано файлов: {{files}}.', + applyRemoveSuccess: 'Удалено меток: {{count}}; обработано файлов: {{files}}.', + actionAdd: 'Добавить к выбранным файлам', + actionRemove: 'Удалить с выбранных файлов', + tagAction: 'Метки', + bulkTitle: 'Метки для выбранных файлов ({{count}})', + bulkTooltip: 'Добавить или удалить метки у всех выбранных файлов.', + noPermission: 'У вас нет прав на изменение меток файлов.', + filterLabel: 'Фильтр по меткам:', + clearAll: 'Очистить всё', + confirmDelete: 'Удалить метку «{{name}}»?', + confirmDeleteMessage: 'Метка будет удалена из каталога. Остальные метки файлов сохранятся.', + confirmDeleteInUseMessage: 'Эта метка назначена файлам ({{count}}). При удалении метка исчезнет у всех файлов; сами файлы не изменятся.', + editAria: 'Изменить {{name}}', + deleteAria: 'Удалить {{name}}', + }, + allTypes: 'Все типы', + prints: 'Файлы печати', + ascending: 'По возрастанию', + descending: 'По убыванию', + resultsCount: 'Показано {{showing}} из {{total}} файлов', + selectAll: 'Выбрать всё', + deselectAll: 'Снять выделение', + selected: 'Выбрано: {{count}}', + adding: 'Добавление...', + loadingFiles: 'Загрузка файлов...', + folderIsEmpty: 'Папка пуста', + noFilesYet: 'Файлов пока нет', + folderEmptyDescription: 'Загрузите или переместите файлы в эту папку.', + noFilesDescription: 'Загрузите файлы, чтобы начать упорядочивать материалы для печати.', + noMatchingFiles: 'Подходящие файлы не найдены', + noMatchingFilesDescription: 'Нет файлов, соответствующих текущему поиску или фильтрам.', + clearFilters: 'Сбросить фильтры', + printedCount: 'Напечатано: {{count}}×', + uploadedBy: 'Загрузил', + deleteFolder: 'Удалить папку', + deleteFile: 'Удалить файл', + deleteFilesCount: 'Удалить файлы ({{count}})', + deleteFolderConfirm: 'Удалить эту папку? Все находящиеся в ней файлы также будут удалены.', + deleteFileConfirm: 'Удалить этот файл?', + deleteFilesConfirm: 'Удалить выбранные файлы ({{count}})? Это действие нельзя отменить.', + deleting: 'Удаление...', + noPermissionRenameFolder: 'У вас нет прав на переименование папок', + noPermissionLinkFolder: 'У вас нет прав на связывание папок', + noPermissionDeleteFolder: 'У вас нет прав на удаление папок', + noPermissionPrint: 'У вас нет прав на запуск печати', + noPermissionAddToQueue: 'У вас нет прав на добавление в очередь', + noPermissionSlice: 'У вас нет прав на нарезку файлов', + noPermissionDownload: 'У вас нет прав на скачивание файлов', + noPermissionRenameFile: 'У вас нет прав на переименование этого файла', + noPermissionGenerateThumbnail: 'У вас нет прав на создание миниатюр', + noPermissionDeleteFile: 'У вас нет прав на удаление этого файла', + noPermissionCreateFolder: 'У вас нет прав на создание папок', + noPermissionUpload: 'У вас нет прав на загрузку файлов', + noPermissionMoveFiles: 'У вас нет прав на перемещение файлов', + noPermissionDeleteFiles: 'У вас нет прав на удаление файлов', + linkExternal: 'Подключить внешнюю папку', + linkExternalFolder: 'Подключить внешнюю папку', + linkExternalFolderDescription: 'Подключить каталог хоста (NAS, USB-накопитель или сетевой ресурс) к файловому менеджеру. Файлы не копируются — Bambuddy обращается к ним по исходному пути.', + externalFolderNamePlaceholder: 'например, Модели на NAS', + externalPath: 'Путь на хосте', + externalPathHelp: 'Абсолютный путь к каталогу на хосте Docker. Каталог должен быть подключён к контейнеру через bind mount.', + readOnly: 'Только чтение', + readOnlyHelp: 'запрещает загрузку и удаление файлов', + showHiddenFiles: 'Показывать скрытые файлы (dotfiles)', + externalFolder: 'Внешняя папка', + scanFolder: 'Сканировать', + toast: { + folderCreated: 'Папка создана', + folderDeleted: 'Папка удалена', + fileDeleted: 'Файл удалён', + filesDeleted: 'Удалено файлов: {{count}}', + filesMoved: 'Файлы перемещены', + folderLinked: 'Папка связана', + folderUnlinked: 'Связь с папкой удалена', + externalFolderLinked: 'Внешняя папка подключена и просканирована', + folderScanned: 'Сканирование завершено: добавлено — {{added}}, удалено — {{removed}}', + addedToQueue: 'Добавлено в очередь файлов: {{count}}', + addedToQueuePartial: 'Добавлено файлов: {{added}}, ошибок: {{failed}}', + failedToAddToQueue: 'Не удалось добавить файлы: {{error}}', + fileRenamed: 'Файл переименован', + folderRenamed: 'Папка переименована', + thumbnailsGenerated: 'Создано миниатюр: {{count}}', + thumbnailsGeneratedPartial: 'Создано миниатюр: {{succeeded}}, ошибок: {{failed}}', + noStlMissingThumbnails: 'Нет STL-файлов без миниатюр', + failedToGenerateThumbnails: 'Не удалось создать миниатюры: {{error}}', + thumbnailGenerated: 'Миниатюра создана', + failedToGenerateThumbnail: 'Не удалось создать миниатюру: {{error}}', + }, + }, + projects: { + title: 'Проекты', + subtitle: 'Организация и отслеживание проектов 3D-печати', + newProject: 'Новый проект', + editProject: 'Изменить проект', + deleteProject: 'Удалить проект', + projectName: 'Название проекта', + description: 'Описание', + noProjects: 'Проектов пока нет', + noProjectsFiltered: 'Нет проектов со статусом «{{status}}»', + noProjectsFilteredHelp: 'У вас нет проектов со статусом «{{status}}». Они появятся здесь после изменения статуса.', + createFirst: 'Создайте первый проект, чтобы объединять связанные печати, отслеживать ход работ и управлять сборкой.', + createFirstButton: 'Создать первый проект', + create: 'Создать', + files: 'Файлы', + prints: 'Печати', + plates: 'пластин', + parts: 'деталей', + lastModified: 'Последнее изменение', + deleteConfirm: 'Удалить этот проект? Архивные записи и элементы очереди будут отвязаны, но не удалены.', + addFiles: 'Добавить файлы', + removeFile: 'Убрать файл', + viewDetails: 'Подробнее', + namePlaceholder: 'например, Сборка Voron 2.4', + descriptionPlaceholder: 'Необязательное описание...', + urlLabel: 'URL', + urlPlaceholder: 'https://makerworld.com/...', + urlInvalid: 'URL должен начинаться с http:// или https://', + openExternalUrl: 'Открыть страницу проекта', + coverImageLabel: 'Обложка', + coverImageAlt: 'Обложка проекта', + coverImageUpload: 'Загрузить', + coverImageReplace: 'Заменить', + coverImageRemove: 'Удалить', + color: 'Цвет', + targetPlates: 'План по пластинам', + targetPlatesPlaceholder: 'например, 25', + targetPlatesHelp: 'Количество заданий печати', + targetParts: 'План по деталям', + targetPartsPlaceholder: 'например, 150', + targetPartsHelp: 'Общее требуемое количество объектов', + tagsLabel: 'Метки (через запятую)', + tagsPlaceholder: 'например, voron, функциональное, подарок', + dueDate: 'Срок', + priority: 'Приоритет', + priorityLow: 'Низкий', + priorityNormal: 'Обычный', + priorityHigh: 'Высокий', + priorityUrgent: 'Срочный', + statusActive: 'Активный', + statusCompleted: 'Завершён', + statusArchived: 'В архиве', + done: 'Готово', + completed: 'завершено', + failed: 'ошибка', + inQueue: 'в очереди', + noPrintsYet: 'Печатей пока нет', + printJobs: 'Задания печати (пластины)', + partsPrinted: 'Напечатано деталей', + failedParts: 'Неудачных деталей', + import: 'Импорт', + export: 'Экспорт', + importProject: 'Импортировать проект', + exportAll: 'Экспортировать все проекты', + loading: 'Загрузка проектов...', + noEditPermission: 'У вас нет прав на изменение проектов', + noDeletePermission: 'У вас нет прав на удаление проектов', + noCreatePermission: 'У вас нет прав на создание проектов', + noImportPermission: 'У вас нет прав на импорт проектов', + noExportPermission: 'У вас нет прав на экспорт проектов', + toast: { + created: 'Проект создан', + updated: 'Проект обновлён', + deleted: 'Проект удалён', + imported: 'Проект импортирован', + multipleImported: 'Импортировано проектов: {{count}}', + importFailed: 'Не удалось импортировать проект', + exported: 'Проекты экспортированы (только метаданные)', + }, + }, + projectDetail: { + notFound: 'Проект не найден', + backToProjects: 'Вернуться к проектам', + export: 'Экспорт', + exportProject: 'Экспортировать проект', + noExportPermission: 'У вас нет прав на экспорт проектов', + noEditPermission: 'У вас нет прав на изменение проектов', + partOf: 'Входит в:', + priorityLabel: 'Приоритет:', + noPrints: 'В этом проекте пока нет печатей', + status: { + active: 'Активный', + completed: 'Завершён', + archived: 'В архиве', + }, + priority: { + low: 'Низкий', + normal: 'Обычный', + high: 'Высокий', + urgent: 'Срочный', + }, + dueDate: { + overdue: 'Срок истёк', + today: 'Срок сегодня', + daysLeft: 'Осталось дней: {{count}}', + }, + progress: { + platesProgress: 'Выполнение по пластинам', + partsProgress: 'Выполнение по деталям', + printJobs: 'заданий печати', + parts: 'деталей', + percentComplete: 'Выполнено {{percent}}%', + remaining: 'Осталось: {{count}}', + }, + stats: { + printJobs: 'Задания печати', + total: 'всего', + failed: 'Неудачных: {{count}}', + partsPrinted: 'Напечатано деталей: {{count}}', + printTime: 'Время печати', + filamentUsed: 'Израсходовано филамента', + }, + cost: { + title: 'Учёт стоимости', + filamentCost: 'Стоимость филамента', + energy: 'Электроэнергия', + totalCost: 'Общая стоимость', + total: 'Итого', + includesBom: 'включая спецификацию', + budget: 'Бюджет', + remaining: 'Остаток', + }, + subProjects: { + title: 'Подпроекты ({{count}})', + }, + notes: { + title: 'Заметки', + noEditPermission: 'У вас нет прав на изменение заметок', + placeholder: 'Добавьте заметки о проекте...', + empty: 'Заметок пока нет. Нажмите «Изменить», чтобы добавить.', + }, + files: { + title: 'Файлы', + linkFolders: 'Свяжите папки из файлового менеджера', + forQuickAccess: 'с этим проектом для быстрого доступа.', + fileCount: 'Файлов: {{count}}', + empty: 'Связанных папок нет. Откройте файловый менеджер и свяжите папку с проектом.', + noFiles: 'В этой папке нет файлов.', + }, + bom: { + title: 'Спецификация', + acquired: 'Приобретено: {{completed}}/{{total}}', + showAll: 'Показать всё', + hideDone: 'Скрыть готовое', + addPart: 'Добавить позицию', + noAddPermission: 'У вас нет прав на добавление позиций', + partNamePlaceholder: 'Название позиции (например, винты M3×8)', + partName: 'Название позиции', + qty: 'Кол-во', + price: 'Цена ({{currency}})', + sourcingUrlPlaceholder: 'Ссылка на поставщика (необязательно)', + remarksPlaceholder: 'Примечание (необязательно)', + deletePart: 'Удалить позицию', + deleteConfirm: 'Удалить «{{name}}»?', + noUpdatePermission: 'У вас нет прав на обновление позиций', + noEditPermission: 'У вас нет прав на изменение позиций', + noDeletePermission: 'У вас нет прав на удаление позиций', + totalCost: 'Общая стоимость:', + empty: 'В спецификации пока нет позиций. Добавьте крепёж, электронику и другие компоненты, закупку которых нужно отслеживать.', + }, + timeline: { + title: 'Хронология активности', + empty: 'Активности пока нет.', + }, + template: { + saveAsTemplate: 'Сохранить как шаблон', + noCreatePermission: 'У вас нет прав на создание шаблонов', + }, + queue: { + title: 'Очередь', + viewAll: 'Показать всё', + printing: 'Печатается: {{count}}', + queued: 'В очереди: {{count}}', + }, + prints: { + title: 'Печати ({{count}})', + }, + toast: { + projectUpdated: 'Проект обновлён', + partAdded: 'Позиция добавлена', + partRemoved: 'Позиция удалена', + exportFailed: 'Не удалось экспортировать', + projectExported: 'Проект экспортирован', + templateCreated: 'Шаблон создан', + }, + }, + system: { + title: 'Информация о системе', + version: 'Версия', + uptime: 'Время работы', + cpuUsage: 'Загрузка процессора', + memoryUsage: 'Использование памяти', + diskUsage: 'Использование диска', + networkInfo: 'Сетевая информация', + logs: 'Журналы', + debugMode: 'Режим отладки', + enableDebug: 'Включить журналирование отладки', + disableDebug: 'Отключить журналирование отладки', + downloadLogs: 'Скачать журналы', + clearLogs: 'Очистить журналы', + dockerInfo: 'Информация о Docker', + containerName: 'Имя контейнера', + imageName: 'Имя образа', + platform: 'Платформа', + architecture: 'Архитектура', + }, + sponsors: { + sectionTitle: 'Независимый проект на поддержке сообщества', + tagline: 'Bambuddy бесплатен и остаётся таким благодаря добровольной поддержке пользователей. Без венчурного капитала и привязки к облаку.', + viewSupporters: 'Посмотреть сторонников проекта', + toastPrints: 'С Bambuddy выполнено печатей: {{count}}. Проект остаётся бесплатным благодаря поддержке сообщества.', + toastCost: 'С помощью Bambuddy учтено филамента на сумму {{total}}. Посмотрите, кто помогает проекту оставаться независимым.', + toastArchives: 'С Bambuddy архивировано печатей: {{count}}. Посмотрите, кто помогает проекту оставаться независимым.', + toastAnniversary: 'Вы уже год с Bambuddy! Посмотрите, кто помогает проекту оставаться независимым.', + toastVersionUpdate: 'Обновлено до версии {{version}}. Bambuddy остаётся бесплатным благодаря поддержке сообщества.', + }, + library: { + title: 'Библиотека филаментов', + addFilament: 'Добавить филамент', + editFilament: 'Изменить филамент', + deleteFilament: 'Удалить филамент', + vendor: 'Производитель', + material: 'Материал', + color: 'Цвет', + kFactor: 'Коэффициент K', + temperature: 'Температура', + noFilaments: 'В библиотеке нет филаментов', + deleteConfirm: 'Удалить этот филамент?', + importFromPrinter: 'Импортировать с принтера', + exportToFile: 'Экспортировать в файл', + runWithPipeline: { + actionLabel: 'Запустить через конвейер', + noPermission: 'У вас нет прав на запуск конвейеров', + modalTitle: 'Запуск через конвейер', + confirmTitle: 'Подтверждение запуска', + confirmIntro: 'Предварительная проверка обнаружила проблемы', + sourceHint: 'Источник', + pipelineHint: 'Конвейер', + targetHint: 'Назначение', + pipelineListAria: 'Доступные конвейеры', + runAnyway: 'Всё равно запустить', + loading: 'Загрузка…', + empty: 'Сохранённых конвейеров пока нет. Откройте диалог нарезки и нажмите «Сохранить как конвейер».', + noTarget: 'Целевой принтер не задан', + noTargetMessage: 'Для этого конвейера не задан целевой принтер. Откройте его в настройках и выберите принтер.', + copies: 'Копии', + copiesHint: 'макс. {{n}}', + classTarget: 'Любой {{model}}', + toast: { + started: 'Конвейер запущен', + failed: 'Не удалось запустить конвейер', + }, + issue: { + printerNotSet: 'Для этого конвейера не задан целевой принтер.', + printerNotFound: 'Целевой принтер больше не существует.', + printerDisabled: 'Целевой принтер отключён.', + printerOffline: 'Целевой принтер не в сети.', + filamentType: 'Слот филамента {{slot}}: ожидается {{expected}}, в AMS установлен {{actual}}', + filamentColor: 'Слот филамента {{slot}}: цвет отличается (ожидается {{expected}}, в AMS установлен {{actual}})', + amsSlotMissing: 'Слот AMS {{slot}} недоступен на этом принтере', + filamentUnverified: 'Филамент в слоте {{slot}} выбран из облачного или стандартного профиля и не может быть проверен заранее.', + noClassMatches: 'Ни один принтер в этой установке не соответствует целевому классу модели конвейера ({{expected}}).', + classNotSet: 'В качестве цели конвейера выбран класс принтера, но модель не указана.', + }, + }, + }, + slice: { + title: 'Нарезка модели', + action: 'Нарезать', + actionAll: 'Нарезать все пластины ({{count}})', + actionAllTitle: 'Нарезать все пластины в один многостольный результат и сохранить в одном архиве. Выбор филаментов охватывает все слоты, используемые проектом.', + allPlatesToggle: 'Нарезать все пластины ({{count}})', + slicing: 'Нарезка…', + printer: 'Профиль принтера', + process: 'Профиль процесса', + filament: 'Профиль филамента', + filamentSlot: 'Филамент {{index}} ({{type}})', + selectPreset: '— Выберите профиль —', + loadingPresets: 'Загрузка профилей…', + analyzingPlateFilaments: 'Анализ филаментов пластины…', + analyzingPlateFilamentsHint: 'Выполняется предварительная нарезка, чтобы определить, какие слоты AMS используются на этой пластине. Результат кэшируется, поэтому повторное открытие будет мгновенным.', + previewToast: 'Анализ {{name}} — {{elapsed}}', + previewWithProgress: 'Анализ {{name}} — {{stage}} ({{percent}}%) — {{elapsed}}', + notUsedByPlate: '— не используется на этой пластине', + noPresetsForSlot: 'Нет доступных профилей', + otherPrinters: 'Другие принтеры', + presetsLoadFailed: 'Не удалось загрузить профили. Сначала импортируйте их в разделе «Настройки → Профили».', + refreshPresets: 'Обновить', + refreshPresetsTitle: 'Обновить профили — получить свежие облачные и встроенные списки. Используйте после удаления профиля в Bambu Studio или Bambu Handy.', + allPresetsRequired: 'Необходимо выбрать все профили', + enqueuing: 'Отправка задания на нарезку…', + queued: 'В очереди…', + failed: 'Ошибка нарезки. Проверьте журналы вспомогательного сервиса слайсера.', + startedToast: 'Фоновая нарезка {{name}}…', + queuedToast: 'В очереди: {{name}} — {{elapsed}}', + runningToast: 'Нарезка {{name}} — {{elapsed}}', + runningWithProgress: '{{name}} — {{stage}} ({{percent}}%) — {{elapsed}}', + runningWithProgressMultiPlate: 'Пластина {{plateIndex}} из {{plateCount}} • {{name}} — {{stage}} ({{percent}}%) — {{elapsed}}', + completedToast: 'Нарезка {{name}} завершена', + failedTitle: 'Ошибка нарезки', + failedToast: 'Не удалось нарезать {{name}}: {{detail}}', + tier: { + local: 'Импортированные', + cloud: 'Bambu Cloud', + orcaCloud: 'Orca Cloud', + standard: 'Стандартные', + }, + cloud: { + notAuthenticated: 'Войдите в Bambu Cloud («Настройки → Профили → Bambu Cloud»), чтобы увидеть облачные профили.', + expired: 'Сессия Bambu Cloud истекла. Войдите снова, чтобы обновить облачные профили.', + unreachable: 'Bambu Cloud сейчас недоступен. Локальные и стандартные профили продолжат работать.', + }, + orcaCloud: { + notAuthenticated: 'Войдите в Orca Cloud («Профили → Orca Cloud»), чтобы увидеть профили Orca.', + expired: 'Сессия Orca Cloud истекла. Войдите снова, чтобы обновить профили Orca.', + unreachable: 'Orca Cloud сейчас недоступен. Остальные профили продолжат работать.', + }, + bedType: { + label: 'Печатная пластина', + auto: 'Авто (из профиля процесса)', + coolPlate: 'Холодная пластина', + coolPlateSuperTack: 'Холодная пластина SuperTack', + engineering: 'Инженерная пластина', + highTemp: 'Высокотемпературная пластина', + texturedPEI: 'Текстурированная PEI-пластина', + smoothPEI: 'Гладкая PEI-пластина', + }, + pipelines: { + label: 'Конвейер', + applyAria: 'Применить конвейер', + applyPrompt: 'Применить конвейер…', + empty: 'Нет сохранённых конвейеров', + saveButton: 'Сохранить как конвейер', + saveTitle: 'Сохранить текущий набор из четырёх профилей как повторно используемый конвейер', + namePlaceholder: 'Название конвейера', + nameAria: 'Название нового конвейера', + toast: { + applied: 'Применён конвейер «{{name}}»', + saved: 'Конвейер сохранён', + saveFailed: 'Не удалось сохранить', + }, + }, + }, + spoolman: { + title: 'Интеграция со Spoolman', + enabled: 'Spoolman включён', + url: 'URL Spoolman', + connected: 'Подключено', + disconnected: 'Нет подключения', + testConnection: 'Проверить подключение', + sync: 'Синхронизировать', + syncing: 'Синхронизация…', + lastSync: 'Последняя синхронизация', + linkToSpoolman: 'Связать со Spoolman', + openInSpoolman: 'Открыть в Spoolman', + unlinkSpool: 'Отвязать катушку', + unlinkConfirmTitle: 'Снять назначение катушки?', + unlinkConfirmMessage: 'Катушка будет удалена из этого слота. Данные самой катушки останутся без изменений.', + selectSpool: 'Выбрать катушку', + noUnlinkedSpools: 'Нет свободных катушек', + linkSuccess: 'Катушка успешно назначена', + linkFailed: 'Не удалось назначить катушку', + unlinkSuccess: 'Назначение катушки снято', + unlinkFailed: 'Не удалось снять назначение катушки', + linkedSpool: 'Назначенная катушка', + spoolId: 'ID катушки', + fillSourceLabel: '(Spoolman)', + weight: 'Масса', + remaining: 'Остаток', + disableWeightSync: 'Отключить синхронизацию расчётной массы AMS', + disableWeightSyncDesc: 'Не обновлять остаток по оценке AMS. Используйте это, если предпочитаете учёт расхода Spoolman процентной оценке AMS. Для новых катушек оценка AMS всё равно будет использована как начальная масса.', + reportPartialUsage: 'Учитывать частичный расход при неудачной печати', + reportPartialUsageDesc: 'Если печать завершилась ошибкой или была отменена, учитывать примерный расход филамента до этого момента по прогрессу слоёв.', + }, + locations: { + title: 'Места хранения', + subtitle: 'Управление полками, ящиками и другими физическими местами хранения катушек', + add: 'Добавить место', + addShort: 'Добавить', + edit: 'Изменить место', + name: 'Название', + spools: 'Катушки', + empty: 'Мест хранения пока нет. Создайте первую полку или ящик.', + manage: 'Места хранения', + createPlaceholder: 'например, Полка A или Ящик 1', + nameRequired: 'Укажите название места хранения', + created: 'Место хранения создано', + updated: 'Место хранения обновлено', + deleted: 'Место хранения удалено', + saveFailed: 'Не удалось сохранить место хранения', + deleteFailed: 'Не удалось удалить место хранения', + deleteBlocked: 'Перед удалением переместите из этого места все катушки', + confirmDelete: 'Удалить «{{name}}»?', + confirmDeleteMessage: 'Это место будет удалено из каталога. Сначала необходимо переместить все катушки.', + }, + inventory: { + title: 'Учёт катушек', + subtitle: 'Управление катушками', + addToInventory: 'Добавить в учёт', + addToInventoryPending: 'Добавление…', + addToInventorySuccess: 'Катушка добавлена в учёт', + addToInventoryFailed: 'Не удалось добавить катушку в учёт', + unknownSpoolTitle: 'Обнаружен новый филамент', + unknownSpoolMessage: 'В {{location}} обнаружена катушка с неизвестной RFID-меткой. Добавить её в учёт?', + unknownSpoolSlot: 'Слот', + bulk: { + selectAllVisible: 'Выбрать все видимые', + selectRow: 'Выбрать строку', + selectGroup: 'Выбрать группу', + selectionCount: 'Выбрано: {{count}}', + edit: 'Изменить', + printLabels: 'Печать этикеток', + resetUsage: 'Сбросить расход', + restore: 'Восстановить', + archive: 'Архивировать', + delete: 'Удалить', + clearSelection: 'Снять выделение', + editTitle: 'Массовое изменение катушек', + editSubtitle: 'Изменения применятся к {{count}} выбранным катушкам. Обновятся только отмеченные поля.', + editHint: 'Введите значение в поле, чтобы включить его обновление. Будут отправлены только отмеченные строки. Пустое поле не изменяет катушки; очистить значение можно только при редактировании отдельной катушки.', + useCustom: 'Использовать «{{value}}»', + toggleField: 'Включить или отключить обновление этого поля', + changeCount: 'Будет обновлено полей: {{count}}.', + applyPending: 'Применение…', + applyButton: 'Применить к {{count}} катушкам', + deleteTitle: 'Удалить выбранные катушки', + archiveTitle: 'Архивировать выбранные катушки', + restoreTitle: 'Восстановить выбранные катушки', + resetUsageTitle: 'Сбросить расход выбранных катушек', + deleteMessage: 'Безвозвратно удалить {{count}} катушек? Это действие нельзя отменить.', + archiveMessage: 'Архивировать {{count}} катушек? Позже их можно будет восстановить.', + restoreMessage: 'Восстановить {{count}} архивных катушек?', + resetUsageMessage: 'Сбросить счётчик «Израсходовано всего» у {{count}} катушек? Текущий остаток массы сохранится.', + updateSuccess: 'Обновлено катушек: {{count}}', + updateFailed: 'Ошибка массового обновления', + updatePartial: 'Обновлено: {{ok}}, с ошибкой: {{failed}}', + updateAllFailed: 'Не удалось обновить все {{count}} катушек. Выделение сохранено для повторной попытки.', + deleteSuccess: 'Удалено катушек: {{count}}', + deleteFailed: 'Ошибка массового удаления', + deletePartial: 'Удалено: {{ok}}, с ошибкой: {{failed}}', + deleteAllFailed: 'Не удалось удалить все {{count}} катушек. Выделение сохранено для повторной попытки.', + archiveSuccess: 'Архивировано катушек: {{count}}', + archiveFailed: 'Ошибка массового архивирования', + archivePartial: 'Архивировано: {{ok}}, с ошибкой: {{failed}}', + archiveAllFailed: 'Не удалось архивировать все {{count}} катушек. Выделение сохранено для повторной попытки.', + restoreSuccess: 'Восстановлено катушек: {{count}}', + restoreFailed: 'Ошибка массового восстановления', + restorePartial: 'Восстановлено: {{ok}}, с ошибкой: {{failed}}', + restoreAllFailed: 'Не удалось восстановить все {{count}} катушек. Выделение сохранено для повторной попытки.', + invalidHex: 'Введите 6 шестнадцатеричных символов (RRGGBB) или 8 (RRGGBBAA), иначе поле не будет применено.', + }, + spoolmanMixedContentTitle: 'Spoolman не загружается через HTTPS: браузер заблокировал смешанное содержимое', + spoolmanMixedContentBody: 'Bambuddy открыт через HTTPS (через обратный прокси), а URL Spoolman всё ещё использует обычный HTTP. Браузер блокирует такое смешанное содержимое, поэтому встроенный интерфейс Spoolman не отображается. Для работы Spoolman должен быть доступен по HTTPS.', + spoolmanMixedContentFixReverseProxy: 'Разместите Spoolman за тем же обратным прокси, что и Bambuddy (Traefik / Nginx / Caddy), включите HTTPS и укажите новый HTTPS-адрес Spoolman в настройках.', + spoolmanMixedContentFixOpenNewTab: 'В качестве обходного решения откройте Spoolman по HTTP в новой вкладке. Ограничение смешанного содержимого действует только для встроенных фреймов.', + spoolmanOpenInNewTab: 'Открыть Spoolman в новой вкладке', + labels: { + title: 'Печать этикеток катушек', + selectedCount: 'Выбрано: {{count}}', + pickSpools: 'Выберите катушки для печати этикеток:', + monochrome: 'Монохромный режим (чёрно-белый принтер)', + monochromeHint: 'Убирает образец цвета и расширяет область текста', + searchPlaceholder: 'Поиск по названию, бренду или #ID', + filterByMaterial: 'Материал:', + allMaterials: 'Все', + selectVisible: 'Выбрать все видимые ({{count}})', + deselectVisible: 'Снять выделение с видимых', + clearAll: 'Очистить выбор', + noSpoolsToShow: 'Нет катушек для отображения. Измените фильтр и повторите попытку.', + noMatches: 'Нет катушек, соответствующих поиску или фильтру.', + printOne: 'Напечатать этикетку этой катушки', + printLabels: 'Печать этикеток…', + bulkTitle: 'Выберите катушки для печати этикеток из {{count}} отображаемых', + noSpoolsTitle: 'Нет катушек для печати этикеток', + error: 'Не удалось создать этикетки: {{msg}}', + sortBy: { + label: 'Сортировка:', + id: 'По ID', + color: 'По цвету', + }, + templates: { + amsHolderSmall: { + label: 'Держатель AMS — малый (74 × 33 мм)', + hint: 'Одна этикетка на страницу; соответствует печатной этикетке для модели MakerWorld 752566 (AMS Filament Label Holder).', + }, + amsHolderLarge: { + label: 'Держатель AMS — большой (75 × 55 мм)', + hint: 'Одна этикетка на страницу; подходит для варианта держателя AMS с картонной вставкой. Достаточно места для образца цвета, бренда, материала, ID и QR-кода.', + }, + box40x30: { + label: 'Этикетка для коробки (40 × 30 мм)', + hint: 'Одна этикетка на страницу; распространённый размер рулона DK/Brother, подходит для пакетов с филаментом и контейнеров хранения.', + }, + box: { + label: 'Этикетка для коробки (62 × 29 мм)', + hint: 'Одна этикетка на страницу; размер для малых этикеток Brother PT/QL и Dymo.', + }, + averyL7160: { + label: 'Avery L7160 — лист A4 (38,1 × 63,5 мм × 21)', + hint: 'Европейский формат: 21 этикетка на листе A4.', + }, + avery5160: { + label: 'Avery 5160 — лист US Letter (25,4 × 66,7 мм × 30)', + hint: 'Американский формат: 30 этикеток на листе Letter.', + }, + }, + }, + csv: { + importButton: 'Импорт CSV', + exportButton: 'Экспорт CSV', + modalTitle: 'Импорт катушек из CSV', + selectFile: 'Выберите CSV-файл или перетащите его сюда', + dragHint: 'Заголовок: material (обязательно), brand, subtype, color_name, rgba, …', + parsing: 'Чтение файла…', + previewError: 'Не удалось прочитать CSV-файл', + validCount: 'Корректных: {{count}}', + errorCount: 'Ошибок: {{count}}', + skippedCount: 'Пропущено: {{count}}', + colRow: 'Строка', + colStatus: 'Состояние', + colColor: 'Цвет', + colorResolved: 'Цвет подставлен из каталога', + colorCrossMaterial: 'Цвет взят у другого материала: точного совпадения в каталоге нет', + duplicateExisting: 'Катушка с таким материалом, брендом и цветом уже существует, но запись всё равно будет импортирована как новая катушка', + spoolmanHint: 'В режиме Spoolman используйте встроенный импорт и экспорт CSV в Spoolman.', + importValidRows: 'Импортировать {{count}} корректных строк', + noValidRows: 'Нет корректных строк', + importing: 'Импорт…', + importSuccess: 'Импортировано катушек: {{count}}', + importError: 'Ошибка импорта', + exportError: 'Ошибка экспорта', + }, + addSpool: 'Добавить катушку', + editSpool: 'Изменить катушку', + copySpool: 'Копировать катушку', + material: 'Материал', + selectMaterial: 'Выберите материал…', + subtype: 'Подтип', + brand: 'Бренд', + searchBrand: 'Поиск бренда…', + useCustomBrand: 'Использовать «{{brand}}»', + useCustomMaterial: 'Использовать свой материал: {{material}}', + colorName: 'Название цвета', + colorNamePlaceholder: 'Jade White, Fire Red…', + color: 'Цвет', + hexColor: 'Цвет HEX', + pickColor: 'Выбрать свой цвет', + labelWeight: 'Номинальная масса', + coreWeight: 'Масса пустой катушки', + searchSpoolWeight: 'Поиск массы катушки…', + weightUsed: 'Израсходовано', + currentWeight: 'Остаток массы', + measuredWeight: 'Измеренная масса', + spoolName: 'Катушка', + costPerKg: 'Стоимость за кг', + storageLocation: 'Место хранения', + storageLocationPlaceholder: 'например, Полка A, Ящик 1', + openInInventory: 'Открыть в учёте', + measuredWeightError: 'Измеренная масса должна быть от {{min}} до {{max}} г.', + slicerFilament: 'Филамент слайсера', + slicerFilamentName: 'Название пресета слайсера', + slicerPreset: 'Пресет слайсера', + searchPresets: 'Поиск пресетов филамента…', + selectedPreset: 'Выбрано', + noPresetsFound: 'Пресеты не найдены', + tempOverrides: 'Переопределение температур', + note: 'Примечание', + notePlaceholder: 'Дополнительные сведения об этой катушке…', + category: 'Категория', + categoryPlaceholder: 'например, Производство, Прототип, Клиент A', + categoryNone: 'Без категории', + storageLocationNone: 'Место не указано', + lowStockThresholdOverride: 'Порог малого остатка (эта катушка)', + lowStockThresholdOverrideHelp: 'Оставьте пустым, чтобы использовать общий порог ({{global}}%).', + clearRfid: 'Очистить RFID-метку', + rfidCleared: 'RFID-метка очищена', + archive: 'Архивировать', + restore: 'Восстановить', + noSpools: 'Катушек пока нет. Добавьте первую катушку.', + noAvailableSpools: 'Нет доступных катушек. Добавьте катушку в учёт или сначала освободите её в другом слоте.', + kProfiles: 'K-профили', + addKProfile: 'Добавить K-профиль', + assignSpool: 'Назначить катушку', + unassignSpool: 'Снять назначение', + assignSuccess: 'Катушка назначена, слот AMS настроен', + assignPendingInsert: 'Катушка назначена. Слот будет настроен после её установки.', + assignFailed: 'Не удалось назначить катушку', + selectSpool: 'Выберите катушку для назначения этому слоту', + assigned: 'Назначено', + assigning: 'Назначение…', + searchSpools: 'Поиск катушек…', + showAllSpools: 'Показать все катушки', + spoolmanSpools: 'Катушки Spoolman', + allMaterials: 'Все материалы', + filterByBrand: 'Фильтр по бренду…', + showArchived: 'Показывать архивные', + quickAdd: 'Быстрое добавление', + quantity: 'Количество', + stock: 'На складе', + configured: 'Настроено', + spoolsCreated: 'Создано катушек: {{count}}', + spoolsPartiallyCreated: 'Создано {{created}} из {{total}} катушек; часть операций завершилась ошибкой', + spoolCreated: 'Катушка создана', + spoolUpdated: 'Катушка обновлена', + spoolDeleted: 'Катушка удалена', + deepLinkSpoolNotFound: 'Катушка не найдена', + deepLinkFetchFailed: 'Не удалось загрузить катушку. Повторите попытку.', + spoolArchived: 'Катушка архивирована', + spoolRestored: 'Катушка восстановлена', + kProfileSaveFailed: 'Не удалось сохранить настройки K-профиля', + syncWeightSpoolNotFound: 'Катушка не найдена: возможно, она была удалена', + syncWeightSpoolmanUnreachable: 'Spoolman недоступен. Повторите попытку позже.', + syncWeightFailed: 'Не удалось синхронизировать массу', + spoolmanUnreachable: 'Spoolman недоступен. Повторите попытку позже.', + deleteSpoolNotFound: 'Катушка не найдена: возможно, она уже удалена', + deleteFailed: 'Не удалось удалить катушку', + archiveSpoolNotFound: 'Катушка не найдена: возможно, она уже удалена', + archiveFailed: 'Не удалось архивировать катушку', + restoreSpoolNotFound: 'Катушка не найдена: возможно, она уже удалена', + restoreFailed: 'Не удалось восстановить катушку', + saveFailed: 'Не удалось сохранить изменения', + tagClearFailed: 'Не удалось очистить метку', + deleteConfirm: 'Удалить эту катушку без возможности восстановления?', + archiveConfirm: 'Архивировать эту катушку?', + advancedSettings: 'Расширенные настройки', + filamentInfoTab: 'Сведения о филаменте', + paProfileTab: 'Профиль PA', + filamentInfo: 'Филамент', + additional: 'Дополнительно', + loadingPresets: 'Загрузка облачных пресетов…', + cloudConnected: 'Облако подключено', + cloudNotConnected: 'Облако не подключено; используются значения по умолчанию', + recentColors: 'Недавние', + searchColors: 'Поиск цветов…', + searchResults: 'Результаты поиска', + allColors: 'Все цвета', + commonColors: 'Основные цвета', + showLess: 'Показать меньше', + showAll: 'Показать все', + noColorsFound: 'Нет цветов, соответствующих запросу', + noResults: 'Совпадений не найдено', + extraColorsLabel: 'Дополнительные цвета', + extraColorsPlaceholder: 'EC984C,#6CD4BC,A66EB9,D87694', + extraColorsHint: 'Вставьте от 2 до 8 HEX-цветов через запятую. Они будут отображены как градиент.', + extraColorsInvalid: 'Пропущены некорректные HEX-значения: {{tokens}}', + colorEffectLabel: 'Эффект', + colorEffect: { + none: 'Нет', + sparkle: 'Блёстки', + wood: 'Дерево', + marble: 'Мрамор', + glow: 'Свечение', + matte: 'Матовый', + silk: 'Шёлк', + galaxy: 'Галактика', + rainbow: 'Радуга', + metal: 'Металл', + translucent: 'Полупрозрачный', + gradient: 'Градиент', + dualColor: 'Двухцветный', + triColor: 'Трёхцветный', + multicolor: 'Многоцветный', + }, + selectMaterialFirst: 'Сначала выберите материал на вкладке «Сведения о филаменте».', + noPrintersConfigured: 'Принтеры не настроены. Добавьте принтеры, чтобы использовать профили PA.', + matchingFilter: 'Совпадающие', + anyBrand: 'Любой бренд', + anyVariant: 'Любой вариант', + autoSelect: 'Автовыбор', + matches: 'совпадений', + match: 'совпадение', + noMatches: 'Нет совпадений', + connected: 'Подключён', + offline: 'Не в сети', + printerOffline: 'Принтер не в сети. Подключите его для просмотра калибровочных профилей.', + noKProfilesMatch: 'Нет K-профилей, соответствующих выбранному филаменту.', + leftNozzle: 'Левое сопло', + rightNozzle: 'Правое сопло', + profilesSelected: 'выбрано калибровочных профилей', + totalInventory: 'Всего в учёте', + totalConsumed: 'Израсходовано всего', + byMaterial: 'По материалам', + inPrinter: 'В принтерах', + lowStock: 'Малый остаток', + sinceTracking: 'С начала учёта', + resetConsumedCounter: 'Сбросить счётчик', + resetConsumedCounterTooltip: 'Обнулить счётчик израсходованных граммов для этой катушки. Остаток массы не изменится.', + resetConsumedCounterConfirm: 'Сбросить счётчик расхода этой катушки до 0? Последующие печати будут учитываться заново. Сама катушка, расчёт остатка и настройки не изменятся.', + resetAllConsumedCounters: 'Сбросить все счётчики', + resetAllConsumedCountersTooltip: 'Обнулить счётчик израсходованных граммов у всех катушек. Остатки массы не изменятся.', + resetAllConsumedCountersConfirm: 'Сбросить счётчик расхода до 0 у всех {{count}} катушек, включая архивные? Показатель «Израсходовано всего» будет очищен, а будущие печати начнут учитываться с нуля. Катушки и их остатки не изменятся.', + consumedCounterReset: 'Счётчик сброшен', + allConsumedCountersReset: 'Счётчик сброшен у {{count}} катушек', + resetConsumedCounterFailed: 'Не удалось сбросить счётчик', + loadedInAms: 'Загружено в AMS/внешний слот', + remaining: 'Остаток', + weightCheck: 'Проверка массы', + lastWeighed: 'Последнее взвешивание', + neverWeighed: 'Не взвешивалась', + search: 'Поиск катушек…', + showing: 'Показано', + to: '–', + of: 'из', + show: 'Показывать', + spools: 'катушек', + spool: 'катушка', + page: 'Страница', + noSpoolsMatch: 'Ничего не найдено', + noSpoolsMatchDesc: 'Измените поисковый запрос или фильтры.', + active: 'Активные', + archived: 'Архивные', + all: 'Все', + used: 'Израсходовано', + new: 'Новые', + clearFilters: 'Сбросить фильтры', + table: 'Таблица', + cards: 'Карточки', + net: 'Нетто', + groupSimilar: 'Группировать', + groupedSpools: 'Одинаковых катушек: {{count}}', + groupedRows: 'строк', + columns: 'Столбцы', + configureColumns: 'Настроить столбцы', + configureColumnsDesc: 'Перетаскивайте столбцы или используйте стрелки для изменения порядка. Видимость переключается значком глаза.', + visible: 'видимых', + reset: 'Сбросить', + cancel: 'Отмена', + applyChanges: 'Применить изменения', + moveUp: 'Переместить вверх', + moveDown: 'Переместить вниз', + hideColumn: 'Скрыть столбец', + showColumn: 'Показать столбец', + linkToSpool: 'Связать с катушкой', + tagLinked: 'Метка связана с катушкой', + tagLinkFailed: 'Не удалось связать метку', + tagAlreadyLinked: 'Метка уже связана с другой катушкой', + unknownTag: 'Обнаружена неизвестная RFID-метка', + usageHistory: 'История расхода', + noUsageHistory: 'Расход пока не зарегистрирован', + printName: 'Название печати', + weightConsumed: 'Израсходованная масса', + clearHistory: 'Очистить', + historyCleared: 'История расхода очищена', + fillSourceLabel: '(Учёт)', + lowStockThresholdError: 'Порог должен быть от 0,1 до 99,9', + assignMismatchTitle: 'Несоответствие материала', + assignMismatchMessage: 'Материал выбранной катушки «{{spoolMaterial}}» не соответствует материалу слота «{{trayMaterial}}» в {{location}}. Всё равно назначить?', + assignMismatchConfirm: 'Всё равно назначить', + assignPartialMismatchMessage: 'Материал катушки «{{spoolMaterial}}» похож, но не совпадает точно с «{{trayMaterial}}» в {{location}}. Продолжить?', + assignProfileMismatchMessage: 'Профиль катушки «{{spoolProfile}}» не соответствует профилю слота «{{trayProfile}}» в {{location}}. Продолжить?', + assignReconfigureNote: 'Слот AMS будет перенастроен на профиль катушки.', + spoolmanFilamentCatalog: 'Каталог филаментов Spoolman', + pickFromSpoolmanCatalog: 'Выбрать из каталога Spoolman…', + spoolmanFilamentSelected: 'Филамент выбран из каталога Spoolman', + spoolmanFilamentUnlinked: 'Связь с каталогом филаментов удалена', + noSpoolmanFilaments: 'В каталоге Spoolman филаменты не найдены', + spoolmanFilamentColorSwatch: 'Цвет филамента', + spoolWeightManagedBySpoolman: 'Масса пустой катушки задаётся в Spoolman для каждого типа филамента', + spoolmanCatalogLoadFailed: 'Не удалось загрузить каталог филаментов Spoolman', + }, + timelapse: { + title: 'Таймлапс', + create: 'Создать таймлапс', + download: 'Скачать', + delete: 'Удалить', + preview: 'Предпросмотр', + frameRate: 'Частота кадров', + quality: 'Качество', + processing: 'Обработка...', + noTimelapses: 'Таймлапсы отсутствуют', + }, + ams: { + title: 'AMS', + slot: 'Слот', + empty: 'Пусто', + emptySlot: 'Пустой слот', + slotEmpty: 'Пусто', + slotUnconfigured: '?', + emptySlotReset: 'Филамент не назначен', + unknown: 'Неизвестно', + humidity: 'Влажность', + temperature: 'Температура', + filamentType: 'Тип филамента', + filamentColor: 'Цвет', + remaining: 'Остаток', + history: 'История AMS', + noHistory: 'История отсутствует', + configureSlot: 'Настроить слот', + externalSpool: 'Внешняя катушка', + profile: 'Профиль', + kFactor: 'Коэффициент K', + fill: 'Заполнить', + configure: 'Настроить', + used: 'использовано', + remainingUnit: 'осталось', + }, + printModal: { + selectPrinter: 'Выберите принтер', + selectPlate: 'Выберите пластину', + filamentMapping: 'Сопоставление филаментов', + totalCost: 'Общая стоимость:', + slotRemainingShort: ' — осталось {{grams}} г', + printSettings: 'Настройки печати', + bedLeveling: 'Калибровка стола', + flowCalibration: 'Калибровка потока', + vibrationCalibration: 'Калибровка вибраций', + layerInspection: 'Проверка первого слоя', + timelapse: 'Таймлапс', + cancel: 'Отмена', + noPrintersAvailable: 'Нет доступных принтеров', + printerBusy: 'Принтер занят', + printerOffline: 'Принтер не в сети', + sameTypeDifferentColor: 'Тот же тип, другой цвет', + filamentTypeNotLoaded: 'Филамент этого типа не загружен', + whenToPrint: 'Когда печатать', + asap: 'Как можно скорее', + queue: 'В очередь', + schedule: 'По расписанию', + dateTime: 'Дата и время', + invalidDateTime: 'Введите корректные дату и время', + openCalendar: 'Открыть календарь', + requireManualStart: 'Требовать ручного запуска', + requirePreviousSuccess: 'Запускать только после успешной предыдущей печати', + autoOffAfter: 'Выключить принтер после завершения', + helpAsap: 'Задание будет добавлено в начало очереди и запустится, как только подходящий принтер освободится.', + helpSchedule: 'Задание запустится в указанное время, если принтер свободен. Если принтер занят, оно будет ждать освобождения.', + helpQueue: 'Задание будет добавлено в конец очереди.', + leftNozzle: 'Л', + rightNozzle: 'П', + leftNozzleTooltip: 'Левое сопло', + rightNozzleTooltip: 'Правое сопло', + filamentOverride: 'Переопределение филаментов', + filamentOverrideHint: 'При необходимости замените филаменты для назначения по модели. Планировщик будет сопоставлять выбранные филаменты вместо исходных значений из 3MF.', + originalFilament: 'Исходный', + overrideWith: 'Заменить на', + resetToOriginal: 'Вернуть исходный', + insufficientFilamentTitle: 'Недостаточно филамента', + insufficientFilamentMessage: 'На некоторых назначенных катушках осталось меньше филамента, чем требуется для этой печати:', + insufficientFilamentLine: '{{printer}} — {{slot}}: требуется {{required}} г, осталось {{remaining}} г', + printAnyway: 'Всё равно печатать', + forceColorMatch: 'Обязательно учитывать цвет', + staggerPrinterStarts: 'Запускать принтеры с задержкой', + staggerGroupSize: 'Размер группы', + staggerInterval: 'Интервал (мин)', + staggerPreview: '{{printers}} принтеров → {{groups}} групп по {{size}}, запуск каждые {{interval}} мин', + staggerLastGroup: 'последняя группа: {{count}}', + staggerTotal: 'всего: {{minutes}} мин', + staggerToPrinters: 'Распределить запуск для {{count}} принтеров', + gcodeInjection: 'Добавить G-code автозапуска', + }, + backup: { + includesEncryptionKey: 'Локальные резервные копии включают файл ключа шифрования MFA (DATA_DIR/.mfa_encryption_key), поэтому ZIP-архив является самодостаточным. Считайте этот ZIP конфиденциальным: любой, у кого есть файл, сможет расшифровать сохранённые в нём секреты клиента OIDC и TOTP.', + title: 'Резервное копирование и восстановление', + createBackup: 'Создать резервную копию', + restoreBackup: 'Восстановить из копии', + restoreDescription: 'Заменить все данные данными из резервной копии', + downloadBackup: 'Скачать резервную копию', + uploadBackup: 'Загрузить резервную копию', + lastBackup: 'Последняя копия', + autoBackup: 'Автоматическое резервное копирование', + backupNow: 'Создать копию сейчас', + restoreWarning: 'Внимание: восстановление из резервной копии перезапишет все текущие данные.', + includeArchives: 'Включить архивы', + includeSettings: 'Включить настройки', + includeProfiles: 'Включить профили', + backupSuccess: 'Резервная копия успешно создана', + restoreSuccess: 'Резервная копия успешно восстановлена', + backupFailed: 'Не удалось создать резервную копию', + restoreFailed: 'Не удалось выполнить восстановление', + restoreNote: 'На время восстановления виртуальный принтер будет остановлен', + githubBackup: 'Резервная копия в Git', + enabled: 'Включено', + cloudLoginRequired: 'Требуется вход в Bambu Cloud. Войдите в разделе «Профили → Облачные профили», чтобы включить резервное копирование в GitHub.', + cloudLoginRequiredShort: 'Требуется вход в облако', + githubDescription: 'Автоматически синхронизировать профили с приватным репозиторием GitHub для резервного копирования и хранения истории версий.', + repoIsPrivate: 'Репозиторий приватный — резервное копирование безопасно.', + repoIsPublicWarning: 'Репозиторий ПУБЛИЧНЫЙ. Резервные копии Bambuddy содержат учётные данные MQTT, токены Home Assistant и Prometheus, адрес электронной почты Bambu Cloud и коды доступа к принтерам из K-профилей. Сохранение заблокировано, пока репозиторий не будет сделан приватным в настройках провайдера.', + repoVisibilityUnknown: 'Не удалось определить видимость репозитория. Bambuddy отказывается создавать резервные копии в репозитории, приватность которого не подтверждена; сохранение будет заблокировано.', + repositoryUrl: 'URL репозитория', + repoUrlPlaceholderGitHub: 'https://github.com/username/repo-name', + repoUrlPlaceholderGitea: 'https://gitea.example.com/username/repo-name', + repoUrlPlaceholderForgejo: 'https://forgejo.example.com/username/repo-name', + repoUrlPlaceholderGitLab: 'https://gitlab.com/username/repo-name', + allowInsecureHttp: 'Разрешить небезопасный HTTP', + allowInsecureHttpHint: 'Включайте для локальных серверов в частной сети без TLS', + personalAccessToken: 'Персональный токен доступа', + tokenSaved: '(сохранён)', + enterNewToken: 'Введите новый токен для обновления', + tokenHint: 'Токен с точечными правами на чтение и запись содержимого', + branch: 'Ветка', + provider: 'Git-провайдер', + providerGitHub: 'GitHub', + providerGitLab: 'GitLab', + providerGitea: 'Gitea', + providerForgejo: 'Forgejo', + manualOnly: 'Только вручную', + hourly: 'Ежечасно', + daily: 'Ежедневно', + weekly: 'Еженедельно', + includeInBackup: 'Включить в резервную копию', + kProfiles: 'K-профили', + kProfilesDescription: 'Калибровки Pressure Advance с подключённых принтеров', + noPrintersConnected: 'Нет подключённых принтеров', + printersConnected: 'Подключено {{connected}} из {{total}}', + cloudProfiles: 'Облачные профили', + cloudProfilesDescription: 'Предустановки филамента, принтера и процесса из Bambu Cloud', + appSettings: 'Настройки приложения', + appSettingsDescription: 'Конфигурация Bambuddy (полная база данных)', + spoolInventory: 'Учёт катушек', + spoolInventoryDescription: 'Катушки филамента, история расхода и учёт стоимости', + printArchives: 'Архив печати', + printArchivesDescription: 'Метаданные истории печати без файлов G-code и 3MF', + lastBackupAt: 'Последняя копия:', + noBackupsYet: 'Резервных копий пока нет', + next: 'Следующая:', + startingBackup: 'Запуск резервного копирования...', + test: 'Проверить', + enableBackup: 'Включить резервное копирование', + testConnection: 'Проверить соединение', + enterRepoUrl: 'Введите URL репозитория', + enterRepoAndToken: 'Введите URL репозитория и токен доступа', + repoRequired: 'Необходимо указать URL репозитория', + tokenRequired: 'Необходимо указать токен доступа', + githubBackupEnabled: 'Резервное копирование в GitHub включено', + tokenUpdated: 'Токен обновлён', + settingsSaved: 'Настройки сохранены', + failedToSave: 'Не удалось сохранить: {{message}}', + backupCompleteFiles: 'Резервное копирование завершено — обновлено файлов: {{count}}', + backupSkippedNoChanges: 'Резервное копирование пропущено — изменений нет', + backupFailed2: 'Ошибка резервного копирования: {{message}}', + clearedLogs: 'Очищено записей журнала: {{count}}', + failedToClearLogs: 'Не удалось очистить журнал: {{message}}', + history: 'История', + clear: 'Очистить', + date: 'Дата', + status: 'Статус', + commit: 'Коммит', + localBackup: 'Локальная резервная копия', + localBackupDescription: 'Создать полную резервную копию данных Bambuddy, включая базу данных, архивы, загрузки и все файлы.', + downloadBackupLabel: 'Скачать резервную копию', + completeBackupZip: 'Полная копия: база данных и все файлы (ZIP)', + download: 'Скачать', + preparingBackup: 'Подготовка резервной копии...', + creatingArchive: 'Создание архива резервной копии... Для больших архивов это может занять некоторое время.', + downloadingFile: 'Скачивание файла резервной копии...', + backupDownloaded: 'Резервная копия успешно скачана', + failedToCreateBackup: 'Не удалось создать резервную копию: {{message}}', + restore: 'Восстановить', + restoreReplacesAll: 'Восстановление заменит все данные.', + restoreReplacesAllDetail: 'Текущая база данных и файлы будут полностью заменены. После восстановления потребуется перезапуск.', + restoreConfirmTitle: 'Восстановление из резервной копии', + restoreConfirmMessage: 'Восстановить данные из файла «{{filename}}»? Текущая база данных и все файлы будут полностью заменены. После восстановления приложение потребуется перезапустить.', + restoreConfirmButton: 'Восстановить', + uploadingFile: 'Загрузка файла резервной копии...', + backupRestoredRestart: 'Резервная копия восстановлена. Перезапустите Bambuddy.', + failedToRestore: 'Не удалось восстановить резервную копию. Проверьте формат файла.', + reloadNow: 'Перезагрузить сейчас', + creatingBackup: 'Создание резервной копии', + restoringBackup: 'Восстановление данных', + preparing: 'Подготовка...', + processing: 'Обработка...', + doNotClosePage: 'Не закрывайте эту страницу и не переходите на другую. Для больших резервных копий операция может занять несколько минут.', + restoring: 'Восстановление...', + restoreComplete: 'Восстановление завершено', + restoreFailed2: 'Ошибка восстановления', + importSettings: 'Импортировать настройки из файла резервной копии', + pleaseWaitRestoring: 'Подождите, пока данные восстанавливаются', + selectBackupFile: 'Нажмите, чтобы выбрать файл резервной копии (.json или .zip)', + duplicateHandling: 'Правила обработки дубликатов:', + matchPrinters: 'Принтеры', + matchPrintersBy: 'сопоставляются по серийному номеру', + matchSmartPlugs: 'Умные розетки', + matchSmartPlugsBy: 'сопоставляются по IP-адресу', + matchNotificationProviders: 'Провайдеры уведомлений', + matchNotificationProvidersBy: 'сопоставляются по имени', + matchFilaments: 'Филаменты', + matchFilamentsBy: 'сопоставляются по имени, типу и бренду', + matchArchives: 'Архивы', + matchArchivesBy: 'сопоставляются по хешу содержимого и всегда пропускаются', + matchPendingUploads: 'Ожидающие загрузки', + matchPendingUploadsBy: 'сопоставляются по имени файла', + matchSettingsTemplates: 'Настройки и шаблоны', + matchSettingsTemplatesBy: 'всегда перезаписываются', + replaceExisting: 'Заменять существующие данные', + keepExisting: 'Сохранять существующие данные', + overwriteDescription: 'Перезаписывать существующие элементы данными из резервной копии', + keepDescription: 'Восстанавливать только отсутствующие элементы', + overwriteCaution: 'Внимание:', + overwriteWarning: 'Перезапись заменит текущие настройки данными из резервной копии. В целях безопасности коды доступа к принтерам никогда не перезаписываются.', + cancel: 'Отмена', + processingBackup: 'Обработка файла резервной копии...', + itemsRestored: 'Восстановлено элементов', + itemsSkipped: 'Пропущено элементов', + restored: 'Восстановлено', + skippedAlreadyExist: 'Пропущено — уже существует', + filesCategory: 'Файлы (3MF, миниатюры и т. п.)', + andMore: '...и ещё {{count}}', + newApiKeysGenerated: 'Созданы новые API-ключи', + keysShownOnce: 'Эти ключи показываются только один раз. Скопируйте их сейчас!', + copy: 'Копировать', + noDataFound: 'В резервной копии не найдено данных для восстановления.', + close: 'Закрыть', + scheduledBackup: 'Резервные копии по расписанию', + scheduledBackupDescription: 'Автоматически создавать снимки резервных копий по расписанию. Каталог назначения можно смонтировать с NAS или внешнего накопителя.', + frequency: 'Периодичность', + backupTime: 'Время', + retention: 'Хранение', + retentionDescription: 'Количество сохраняемых резервных копий', + outputPath: 'Каталог назначения', + outputPathPlaceholder: 'По умолчанию: {{path}}', + outputPathDescription: 'Оставьте пустым, чтобы использовать стандартный каталог', + runNow: 'Запустить сейчас', + backupFiles: 'Файлы резервных копий', + noScheduledBackups: 'Резервных копий пока нет', + deleteBackup: 'Удалить', + deleteBackupConfirm: 'Удалить этот файл резервной копии?', + backupRunning: 'Выполняется резервное копирование...', + scheduledBackupComplete: 'Резервная копия успешно создана', + scheduledBackupFailed: 'Ошибка резервного копирования', + nextBackup: 'Следующая копия', + backupSize: 'Размер', + localTimeHint: 'Местное время ({{tz}})', + defaultPathLabel: 'По умолчанию:', + categories: { + settings: 'Настройки', + notification_providers: 'Провайдеры уведомлений', + notification_templates: 'Шаблоны уведомлений', + smart_plugs: 'Умные розетки', + printers: 'Принтеры', + filaments: 'Филаменты', + maintenance_types: 'Виды обслуживания', + archives: 'Архивы', + projects: 'Проекты', + pending_uploads: 'Ожидающие загрузки', + external_links: 'Внешние ссылки', + api_keys: 'API-ключи', + }, + }, + tags: { + title: 'Метки', + addTag: 'Добавить метку', + editTag: 'Изменить метку', + deleteTag: 'Удалить метку', + tagName: 'Название метки', + tagColor: 'Цвет метки', + noTags: 'Меток нет', + deleteConfirm: 'Удалить эту метку?', + manageTags: 'Управление метками', + }, + uploadModal: { + title: 'Загрузка файлов 3MF', + dragDrop: 'Перетащите файлы .3mf сюда', + or: 'или', + browseFiles: 'Выбрать файлы', + extractionInfo: 'Модель принтера будет автоматически определена по метаданным файла 3MF.', + uploaded: 'загружено', + failed: 'ошибок', + uploading: 'Загрузка...', + upload: 'Загрузить', + uploadFailed: 'Не удалось загрузить', + }, + editArchive: { + title: 'Редактирование архива', + name: 'Название', + namePlaceholder: 'Название печати', + printer: 'Принтер', + noPrinter: 'Без принтера', + project: 'Проект', + noProject: 'Без проекта', + itemsPrinted: 'Напечатано изделий', + itemsPrintedHelp: 'Количество изделий, полученных в этом задании печати', + notes: 'Заметки', + notesPlaceholder: 'Добавьте заметки об этой печати...', + externalLink: 'Внешняя ссылка', + externalLinkPlaceholder: 'https://printables.com/model/...', + externalLinkHelp: 'Ссылка на Printables, Thingiverse или другой источник', + tags: 'Метки', + tagsPlaceholder: 'Добавить метки...', + addMoreTags: 'Добавить ещё метки...', + matchingTags: 'Совпадения для «{{query}}»', + existingTags: 'Существующие метки', + clickToAdd: '(нажмите, чтобы добавить)', + status: 'Статус', + failureReason: 'Причина сбоя', + selectReason: 'Выберите причину...', + photos: 'Фотографии результата печати', + photosHelp: 'Нажмите +, чтобы добавить фотографии результата', + printResult: 'Результат печати', + saving: 'Сохранение...', + failureReasons: { + adhesionFailure: 'Плохая адгезия к столу', + spaghettiDetached: 'Спагетти / отрыв детали', + layerShift: 'Сдвиг слоёв', + cloggedNozzle: 'Засор сопла', + filamentRunout: 'Закончился филамент', + warping: 'Коробление', + stringing: 'Стрингинг', + underExtrusion: 'Недоэкструзия', + powerFailure: 'Сбой питания', + userCancelled: 'Отменено пользователем', + other: 'Другое', + }, + statuses: { + completed: 'Завершено', + failed: 'Ошибка', + aborted: 'Отменено', + printing: 'Печать', + }, + }, + virtualPrinter: { + title: 'Виртуальный принтер', + running: 'Запущен', + stopped: 'Остановлен', + description: { + default: 'Включает виртуальный принтер, который отображается в Bambu Studio и OrcaSlicer. Отправленные на него файлы сразу сохраняются в архив без печати.', + proxy: 'Включает прокси, перенаправляющий трафик слайсера на реальный принтер и позволяющий печатать удалённо из любой сети.', + }, + enable: { + title: 'Включить виртуальный принтер', + visibleInSlicer: 'Отображается как «Bambuddy» при обнаружении принтеров в слайсере', + proxyingTo: 'Проксирование на {{name}}', + notActive: 'Не активен', + }, + model: { + title: 'Модель принтера', + description: 'Выберите модель принтера, которую нужно эмулировать.', + restartWarning: 'При изменении модели виртуальный принтер будет перезапущен', + }, + accessCode: { + title: 'Код доступа', + isSet: 'Код доступа задан', + notSet: 'Код доступа не задан — он необходим для включения', + placeholder: 'Введите 8-значный код', + placeholderChange: 'Введите новый код', + hint: 'Код должен состоять ровно из 8 символов. Слайсеры используют его для аутентификации.', + charCount: '({{count}}/8)', + inheritedFromTarget: 'Унаследован от целевого принтера', + derivedFromTargetHint: 'Используется код доступа целевого принтера. Мост перенаправляет аутентификацию слайсера на реальный принтер, поэтому коды должны совпадать. Чтобы изменить значение, измените код доступа самого принтера.', + reveal: 'Показать код доступа', + hide: 'Скрыть код доступа', + }, + targetPrinter: { + title: 'Целевой принтер', + configured: 'Целевой принтер для прокси настроен', + notConfigured: 'Целевой принтер не выбран — он необходим для режима прокси', + placeholder: 'Выберите принтер...', + hint: 'Выберите принтер, на который будет перенаправляться трафик слайсера. Принтер должен работать в режиме LAN.', + noPrinters: 'Нет настроенных принтеров. Сначала добавьте принтер.', + }, + remoteInterface: { + title: 'Переопределение сетевого интерфейса', + configured: 'Переопределение интерфейса активно', + optional: 'Необязательно — используйте, если IP определён неверно, например при нескольких сетевых картах, Docker или VPN', + placeholder: 'Определять автоматически...', + hint: 'Переопределяет IP-адрес, публикуемый через SSDP и используемый в TLS-сертификате. Полезно, если у Bambuddy несколько сетевых интерфейсов.', + }, + mode: { + title: 'Режим', + archive: 'Архив', + archiveDesc: 'Сразу сохранять файлы в архив', + review: 'Проверка', + reviewDesc: 'Проверять перед добавлением в архив', + queue: 'Очередь', + queueDesc: 'Сохранять в архив и добавлять в очередь', + proxy: 'Прокси', + proxyDesc: 'Перенаправлять на реальный принтер', + }, + autoDispatch: { + title: 'Автоматический запуск', + description: 'Автоматически запускать задания после добавления в очередь. Если выключено, задания ожидают ручного запуска.', + }, + queueForceColorMatch: { + title: 'Требовать совпадения цвета', + description: 'Не назначать задание принтеру, если загружены филамент другого типа или другого цвета. По умолчанию выключено: без этой проверки очередь сопоставляет только модель принтера и может выбрать принтер с неподходящим цветом.', + }, + gcodeInjection: { + title: 'Вставка G-code', + description: 'Применять к заданиям этого виртуального принтера фрагменты G-code для соответствующей модели, заданные в настройках. По умолчанию выключено.', + }, + tailscaleDisabled: { + title: 'Интеграция Tailscale', + description: 'Отметить этот виртуальный принтер как доступный через Tailscale. Будет показан Tailscale-адрес хоста, который нужно указать в слайсере. Импорт сертификата центра сертификации выполняется как обычно; этот переключатель на сертификаты не влияет.', + }, + setupRequired: { + title: 'Требуется настройка', + description: 'Для работы виртуального принтера требуется дополнительная настройка системы: перенаправление портов, правила межсетевого экрана и параметры, зависящие от платформы.', + readGuide: 'Перед включением прочитайте руководство по настройке', + }, + archiveNameSource: { + title: 'Источник названия архива', + description: 'Выберите способ формирования названия новых архивов для файлов, полученных через виртуальный принтер. «Метаданные» использует поле Title, встроенное слайсером в 3MF. «Имя файла» использует имя, переданное Bambu Studio по FTP. Bambu Studio заменяет введённое в окне отправки название значением Title из 3MF, если оно присутствует, поэтому оба режима часто дают одинаковый результат.', + metadata: 'Метаданные', + filename: 'Имя файла', + }, + caCert: { + title: 'Сертификат для слайсера', + description: 'Виртуальные принтеры используют TLS-сертификат, подписанный центром сертификации Bambuddy. Один раз импортируйте этот сертификат CA в хранилище доверенных сертификатов слайсера, чтобы он принимал соединение.', + copy: 'Копировать', + copied: 'Скопировано', + download: 'Скачать', + fingerprint: 'SHA-256', + }, + howItWorks: { + title: 'Как это работает', + step1: 'В одной локальной сети виртуальные принтеры автоматически появляются в Bambu Studio и OrcaSlicer. Из других сетей добавьте их вручную по IP-адресу и коду доступа.', + step2: 'В режимах «Архив», «Проверка» и «Очередь» используйте кнопку «Отправить» в слайсере для загрузки 3MF в Bambuddy. Слайсер покажет сообщение об успешной печати, но файл будет только сохранён, без запуска печати.', + step3: 'В режиме прокси виртуальный принтер перенаправляет весь трафик на реальный принтер — печать запускается сразу, как при прямом подключении.', + }, + status: { + title: 'Сведения о состоянии', + printerName: 'Имя принтера', + model: 'Модель', + serialNumber: 'Серийный номер', + mode: 'Режим', + pendingFiles: 'Ожидающие файлы', + targetPrinter: 'Целевой принтер', + ftpPort: 'Порт FTP', + mqttPort: 'Порт MQTT', + ftpConnections: 'Соединения FTP', + mqttConnections: 'Соединения MQTT', + }, + toast: { + updated: 'Настройки виртуального принтера обновлены', + failedToUpdate: 'Не удалось обновить настройки', + copyFailed: 'Не удалось скопировать — выделите текст вручную', + accessCodeRequired: 'Сначала задайте код доступа', + targetPrinterRequired: 'Сначала выберите целевой принтер', + bindIpRequired: 'Сначала задайте IP-адрес привязки', + accessCodeEmpty: 'Код доступа не может быть пустым', + accessCodeLength: 'Код доступа должен состоять ровно из 8 символов', + targetCodeChangedRebind: 'Код доступа приведён в соответствие с новым целевым принтером. Удалите и снова добавьте устройство в слайсере, чтобы он получил новый код.', + created: 'Виртуальный принтер создан', + failedToCreate: 'Не удалось создать виртуальный принтер', + deleted: 'Виртуальный принтер удалён', + failedToDelete: 'Не удалось удалить виртуальный принтер', + }, + list: { + title: 'Виртуальные принтеры', + add: 'Добавить', + addFirst: 'Добавить виртуальный принтер', + empty: 'Виртуальные принтеры не настроены. Добавьте первый принтер.', + }, + bindIp: { + title: 'Интерфейс привязки', + placeholder: 'Выберите интерфейс...', + hint: 'Сетевой интерфейс, к которому будет привязан этот виртуальный принтер. Для каждого принтера он должен быть уникальным.', + }, + proxy: { + accessCodeHint: 'В режиме прокси используйте в слайсере код доступа целевого принтера. Соединение прозрачно перенаправляется на реальный принтер.', + }, + addDialog: { + title: 'Добавление виртуального принтера', + name: 'Название', + hint: 'После создания можно настроить код доступа, целевой принтер и остальные параметры.', + create: 'Создать', + }, + deleteConfirm: { + title: 'Удаление виртуального принтера', + message: 'Удалить «{{name}}»? Все службы этого виртуального принтера будут остановлены.', + }, + }, + modelViewer: { + openInSlicer: 'Открыть в слайсере', + tabs: { + model: '3D-модель', + gcode: 'Предпросмотр G-code', + }, + notAvailable: 'недоступно', + notSliced: 'не нарезано', + plates: 'Пластины', + allPlates: 'Все пластины', + plateNumber: 'Пластина {{number}}', + plateCount: '{{count}} пластина', + plateCount_other: '{{count}} пластин', + objectCount: '{{count}} объект', + objectCount_other: '{{count}} объектов', + filamentCount: '{{count}} филамент', + filamentCount_other: '{{count}} филаментов', + eta: 'Осталось {{minutes}} мин', + noPreview: 'Для этого файла нет предпросмотра', + pagination: { + pageOf: 'Страница {{current}} из {{total}}', + prev: 'Назад', + next: 'Далее', + }, + errors: { + failedToLoad: 'Не удалось загрузить файл', + noMeshes: 'В файле 3MF не найдены сеточные модели', + unsupportedFormat: 'Неподдерживаемый формат файла', + }, + }, + maintenanceDescriptions: { + lubricateCarbonRods: 'Смазать углепластиковые направляющие для плавного перемещения', + lubricateRails: 'Смазать линейные направляющие для плавного перемещения', + cleanNozzle: 'Очистить хотэнд и сопло для предотвращения засоров', + checkBelts: 'Проверить натяжение ремней для сохранения точности печати', + cleanBuildPlate: 'Очистить печатную пластину для улучшения адгезии', + checkExtruder: 'Проверить шестерни экструдера на износ', + checkCooling: 'Проверить исправность вентиляторов охлаждения', + generalInspection: 'Общий осмотр принтера', + cleanCarbonRods: 'Очистить углепластиковые направляющие для уменьшения трения', + lubricateSteelRods: 'Смазать стальные направляющие для плавного перемещения', + cleanSteelRods: 'Очистить стальные направляющие для уменьшения трения', + cleanLinearRails: 'Протереть линейные направляющие от пыли и загрязнений', + checkPtfeTube: 'Проверить PTFE-трубку на износ и повреждения', + replaceHepaFilter: 'Заменить HEPA-фильтр', + replaceCarbonFilter: 'Заменить угольный фильтр', + lubricateLeftNozzleRail: 'Смазать направляющую левого сопла (серия H2)', + }, + smartPlugs: { + offline: 'Не в сети', + admin: 'Управление', + openPlugAdminPage: 'Открыть страницу управления розеткой', + deleteSmartPlug: 'Удалить умную розетку', + turnOnSmartPlug: 'Включить умную розетку', + turnOffSmartPlug: 'Выключить умную розетку', + turnOn: 'Включить', + turnOff: 'Выключить', + addSmartPlug: { + scanningNetwork: 'Сканирование сети...', + chooseEntity: 'Выберите сущность...', + connectionFailed: 'Ошибка подключения', + searchEntities: 'Поиск сущностей...', + searchPowerSensors: 'Поиск датчиков мощности...', + searchEnergySensors: 'Поиск датчиков энергии...', + placeholders: { + plugName: 'Розетка в гостиной', + mqttStateOnValue: 'ON, true, 1', + mqttSameAsPower: 'Та же тема, что для мощности, или другая', + }, + }, + linkedTo: 'Связана с:', + monitorOnly: 'Только мониторинг', + alerts: 'Оповещения', + scheduleOn: 'Включение в {{time}}', + scheduleOff: 'Выключение в {{time}}', + on: 'Включена', + off: 'Выключена', + power: 'Мощность', + kwhToday: 'кВт·ч сегодня', + settings: 'Настройки', + automationSettings: 'Настройки автоматизации', + showInSwitchbar: 'Показывать на панели переключателей', + quickAccessSidebar: 'Быстрый доступ с боковой панели', + enabled: 'Включено', + enableAutomation: 'Включить автоматизацию для этой розетки', + autoOn: 'Автовключение', + autoOnDescription: 'Включать при начале печати', + autoOff: 'Автовыключение', + autoOffDescription: 'Выключать после завершения печати (однократно)', + autoOffPersistent: 'Оставлять включённым', + autoOffPersistentDescription: 'Не сбрасывать автовыключение после печати', + autoOffAfterDrying: 'Выключать после сушки', + autoOffAfterDryingDescription: 'Выключать после завершения сушки в AMS', + delayAfterDryingMinutes: 'Задержка после сушки (мин)', + turnOffDelayMode: 'Условие отложенного выключения', + time: 'Время', + temp: 'Температура', + delayMinutes: 'Задержка (мин)', + tempThreshold: 'Порог температуры (°C)', + tempThresholdDescription: 'Выключать, когда сопло остынет ниже этой температуры', + edit: 'Изменить', + deleteConfirm: 'Удалить «{{name}}»? Это действие нельзя отменить.', + turnOnConfirm: 'Включить «{{name}}»?', + turnOffConfirm: 'Выключить «{{name}}»? Питание подключённого устройства будет отключено.', + failedToTurn: 'Не удалось {{action}} «{{name}}»', + unknown: 'Неизвестно', + addTitle: 'Добавление умной розетки', + editTitle: 'Редактирование умной розетки', + stopScanning: 'Остановить сканирование', + discoverTasmota: 'Найти устройства Tasmota', + foundDevices: 'Найдено устройств: {{count}}. Нажмите для выбора:', + noDevicesFound: 'Устройства Tasmota в сети не найдены', + haNotConfigured: 'Home Assistant не настроен. Настройте его в разделе', + haSettingsPath: 'Настройки → Сеть → Home Assistant', + selectEntity: 'Выберите сущность *', + ipAddress: 'IP-адрес *', + nameLabel: 'Название *', + username: 'Имя пользователя', + password: 'Пароль', + authHint: 'Оставьте пустым, если устройство Tasmota не требует аутентификации', + linkToPrinter: 'Связать с принтером', + noPrinter: 'Без принтера — только ручное управление', + linkingDescription: 'Связь позволяет автоматически включать и выключать питание при начале и завершении печати', + powerAlerts: 'Оповещения о мощности', + alertAbove: 'Оповещать выше (Вт)', + alertBelow: 'Оповещать ниже (Вт)', + alertDescription: 'Отправлять уведомление при пересечении заданных порогов мощности. Оставьте поле пустым, чтобы отключить соответствующий порог.', + dailySchedule: 'Ежедневное расписание', + turnOnAt: 'Включать в', + turnOffAt: 'Выключать в', + scheduleDescription: 'Ежедневно включать и выключать розетку в указанное время. Оставьте поле пустым, чтобы не выполнять соответствующее действие.', + showOnPrinterCard: 'Показывать в карточке принтера', + displayOnPrinterCard: 'Показывать кнопку в карточке принтера', + connectedResult: 'Подключено!', + deviceLabel: 'Устройство: {{name}} — ', + stateLabel: 'Состояние: {{state}}', + test: 'Проверить', + delete: 'Удалить', + save: 'Сохранить', + add: 'Добавить', + cancel: 'Отмена', + failedToStartScan: 'Не удалось запустить сканирование', + nameRequired: 'Укажите название', + entityRequired: 'Для розеток Home Assistant необходимо выбрать сущность', + mqttTopicRequired: 'Для мониторинга мощности, энергии или состояния необходимо настроить хотя бы одну тему MQTT', + loadingEntities: 'Загрузка сущностей...', + loading: 'Загрузка...', + failedToLoadEntities: 'Не удалось загрузить сущности: {{error}}', + noEntitiesMatching: 'Сущности по запросу «{{search}}» не найдены', + noEntitiesAvailable: 'Нет доступных сущностей', + searchingEntities: 'Поиск по всем сущностям, найдено: {{count}}', + showingEntities: 'Показаны switch, light и input_boolean, доступно: {{count}}', + energyMonitoringOptional: 'Мониторинг энергии (необязательно)', + energyMonitoringHint: 'Найдите и выберите датчики мощности и энергии.', + powerSensorW: 'Датчик мощности (Вт)', + energyTodayKwh: 'Энергия за сегодня (кВт·ч)', + totalEnergyKwh: 'Общая энергия (кВт·ч)', + noMatchingSensors: 'Подходящие датчики не найдены', + none: 'Нет', + mqttNotConfigured: 'Брокер MQTT не настроен. Укажите его адрес в разделе', + mqttSettingsPath: 'Настройки → Сеть → Публикация MQTT', + mqttNotConfiguredSuffix: 'Включать публикацию не обязательно — достаточно заполнить параметры брокера.', + mqttMonitorOnlyDescription: 'Розетки MQTT получают данные мощности и энергии через подписку MQTT. Управление включением и выключением недоступно — используйте брокер MQTT или систему домашней автоматизации.', + powerMonitoring: 'Мониторинг мощности', + energyMonitoring: 'Мониторинг энергии', + stateMonitoring: 'Мониторинг состояния', + optional: 'необязательно', + topic: 'Тема', + jsonPath: 'Путь JSON', + multiplier: 'Множитель', + onValue: 'Значение «включено»', + mqttPowerHint: 'Путь JSON извлекает значение из полезной нагрузки JSON, например «power_l1». Оставьте пустым, если тема публикует число напрямую.\nДля преобразования мВт→Вт используйте 0.001, для кВт→Вт — 1000.', + mqttEnergyHint: 'Путь JSON извлекает значение из полезной нагрузки JSON. Оставьте пустым для числового значения напрямую.\nДля преобразования Вт·ч→кВт·ч используйте 0.001, для МВт·ч→кВт·ч — 1000.', + mqttStateHint: 'Путь JSON извлекает значение из полезной нагрузки JSON. Оставьте пустым для значения напрямую.\nЗначение «включено» — точная строка, означающая включённое состояние. Оставьте пустым для автоматического распознавания ON, true и 1.', + restControl: 'Управление', + restOnUrl: 'URL включения', + restOffUrl: 'URL выключения', + restOnBody: 'Тело запроса включения', + restOffBody: 'Тело запроса выключения', + restMethod: 'Метод HTTP', + restHeaders: 'Пользовательские заголовки (JSON)', + restStatusUrl: 'URL состояния', + restStatusPath: 'Путь JSON состояния', + restStatusOnValue: 'Значение «включено»', + restPowerUrl: 'URL мощности', + restPowerPath: 'Путь JSON мощности', + restPowerMultiplier: 'Множитель мощности', + restEnergyUrl: 'URL энергии', + restEnergyPath: 'Путь JSON энергии', + restEnergyMultiplier: 'Множитель энергии', + restUrlRequired: 'Для REST-розетки необходимо указать хотя бы один URL: включения или выключения', + restHeadersHint: 'например, {"Authorization": "Bearer your-token"}', + restBodyHint: 'например, ON или {"state": "on"}', + restStatusHint: 'URL для опроса текущего состояния', + restPathHint: 'например, state или data.power.status', + restPowerUrlHint: 'Отдельный URL данных мощности; если пусто, используется URL состояния', + restEnergyUrlHint: 'Отдельный URL данных энергии; если пусто, используется URL состояния', + restEnergyHint: 'Для каждого значения можно использовать отдельный URL либо URL состояния. Множители используются для преобразования единиц, например 0.001 для Вт·ч→кВт·ч.', + testConnection: 'Проверить подключение', + connectionSuccess: 'Подключение успешно', + noSwitchesInSwitchbar: 'На панели переключателей нет устройств', + enableSwitchbarHint: 'Включите «Показывать на панели переключателей» в разделе «Настройки → Умные розетки»', + }, + notifications: { + providerTypes: { + callmebot: 'CallMeBot/WhatsApp', + ntfy: 'ntfy', + pushover: 'Pushover', + telegram: 'Telegram', + email: 'Электронная почта', + discord: 'Discord', + webhook: 'Вебхук', + homeassistant: 'Home Assistant', + }, + providerDescriptions: { + email: 'Уведомления по электронной почте через SMTP', + telegram: 'Уведомления через Telegram-бота', + discord: 'Отправка в канал Discord через вебхук', + ntfy: 'Бесплатные push-уведомления с возможностью самостоятельного размещения сервера', + pushover: 'Простые и надёжные push-уведомления', + callmebot: 'Бесплатные уведомления WhatsApp через CallMeBot', + webhook: 'Универсальный HTTP POST-запрос на любой URL', + homeassistant: 'Постоянные уведомления на панели Home Assistant', + }, + lastSuccess: 'Последняя отправка: {{date}}', + error: 'Ошибка', + printer: 'Принтер:', + allPrinters: 'Все принтеры', + sendTestNotification: 'Отправить тестовое уведомление', + eventSettings: 'Настройки событий', + enabled: 'Включено', + sendFromProvider: 'Отправлять уведомления через этого провайдера', + printEvents: 'События печати', + printerStatus: 'Состояние принтера', + amsAlarms: 'Предупреждения AMS', + amsHtAlarms: 'Предупреждения AMS-HT', + printQueue: 'Очередь печати', + start: 'Запуск', + plateCheck: 'Проверка пластины', + complete: 'Завершено', + failed: 'Ошибка', + stopped: 'Остановлено', + progress: 'Ход печати', + offline: 'Не в сети', + lowFilament: 'Мало филамента', + maintenance: 'Обслуживание', + amsHumidity: 'Влажность AMS', + amsTemp: 'Температура AMS', + amsHtHumidity: 'Влажность AMS-HT', + amsHtTemp: 'Температура AMS-HT', + bedCooled: 'Стол остыл', + firstLayer: 'Первый слой', + quiet: 'Тихий режим', + digest: 'Сводка в {{time}}', + printStarted: 'Печать началась', + plateNotEmpty: 'Пластина не пуста', + plateNotEmptyDescription: 'Перед печатью на пластине обнаружены объекты', + printCompleted: 'Печать завершена', + bedCooledLabel: 'Стол остыл', + bedCooledDescription: 'После печати температура стола опустилась ниже заданного порога', + firstLayerCompleteLabel: 'Первый слой завершён', + firstLayerCompleteDescription: 'Уведомить со снимком после завершения первого слоя', + missingSpoolAssignmentLabel: 'Катушка не назначена', + missingSpoolAssignmentDescription: 'Уведомить при запуске печати, если для необходимых слотов не назначены катушки', + printFailed: 'Ошибка печати', + printStopped: 'Печать остановлена', + progressMilestones: 'Этапы выполнения', + progressMilestonesDescription: 'Уведомлять при 25%, 50% и 75%', + printerOffline: 'Принтер не в сети', + printerError: 'Ошибка принтера', + aiFailureDetection: 'Обнаружение сбоев с помощью ИИ', + aiFailureDetectionDescription: 'Уведомить, если Obico AI обнаружит возможный сбой печати', + lowFilamentLabel: 'Заканчивается филамент', + maintenanceDue: 'Требуется обслуживание', + maintenanceDueDescription: 'Уведомить, когда принтеру потребуется обслуживание', + amsHumidityHigh: 'Высокая влажность в AMS', + amsHumidityHighDescription: 'Влажность в обычной AMS превысила заданный порог', + amsTemperatureHigh: 'Высокая температура в AMS', + amsTemperatureHighDescription: 'Температура в обычной AMS превысила заданный порог', + amsHtHumidityHigh: 'Высокая влажность в AMS-HT', + amsHtHumidityHighDescription: 'Влажность в AMS-HT превысила заданный порог', + amsHtTemperatureHigh: 'Высокая температура в AMS-HT', + amsHtTemperatureHighDescription: 'Температура в AMS-HT превысила заданный порог', + inventoryAlerts: 'Уведомления о запасах', + stockReorderAlert: 'Пора заказывать', + stockReorderAlertDescription: 'Запас по SKU достиг точки повторного заказа', + stockBreakAlert: 'Риск исчерпания запаса', + stockBreakAlertDescription: 'Запас закончится раньше, чем поступит пополнение', + jobAdded: 'Задание добавлено', + jobAddedDescription: 'Задание добавлено в очередь', + jobAssigned: 'Задание назначено', + jobAssignedDescription: 'Задание по модели назначено принтеру', + jobStarted: 'Задание запущено', + jobStartedDescription: 'Задание из очереди отправлено на печать', + jobWaiting: 'Задание ожидает', + jobWaitingDescription: 'Задание ожидает филамент или свободный принтер', + jobSkipped: 'Задание пропущено', + jobSkippedDescription: 'Задание пропущено из-за ошибки предыдущего', + jobFailed: 'Не удалось запустить задание', + jobFailedDescription: 'Задание не удалось отправить на печать', + queueComplete: 'Очередь завершена', + queueCompleteDescription: 'Все задания в очереди завершены', + quietHours: 'Тихие часы', + noNotificationsDuring: 'Не отправлять уведомления в это время', + editProviderToChangeQuietHours: 'Измените провайдера, чтобы настроить тихие часы', + dailyDigest: 'Ежедневная сводка', + batchNotifications: 'Объединять уведомления в одну ежедневную сводку', + sendAt: 'Отправлять в {{time}}', + editProviderToChangeDigestTime: 'Измените провайдера, чтобы настроить время сводки', + edit: 'Изменить', + deleteProvider: 'Удалить провайдера уведомлений', + deleteConfirm: 'Удалить «{{name}}»? Это действие нельзя отменить.', + delete: 'Удалить', + addTitle: 'Добавить провайдера уведомлений', + editTitle: 'Изменить провайдера уведомлений', + nameLabel: 'Название *', + namePlaceholder: 'Мои уведомления', + providerTypeLabel: 'Тип провайдера *', + configuration: 'Настройка', + testConfiguration: 'Проверить настройку', + printerFilter: 'Фильтр принтеров', + onlyFromPrinter: 'Отправлять уведомления только о событиях этого принтера', + quietHoursDnd: 'Тихие часы (не беспокоить)', + quietStart: 'Начало', + quietEnd: 'Окончание', + dailyDigestLabel: 'Ежедневная сводка', + sendDigestAt: 'Отправлять сводку в', + digestCollected: 'События будут собраны и отправлены одной сводкой в указанное время', + notificationEvents: 'События для уведомлений', + progressPercent: '(25%, 50%, 75%)', + bedCooledAfterPrint: '(после завершения печати)', + eventPriority: { + sectionTitle: 'Приоритет ntfy', + helpNtfy: 'Выберите приоритет для каждого включённого события. ntfy использует его для усиления оповещений: звука, видимости и поведения push-уведомлений. Для неуказанных событий используется приоритет по умолчанию сервера ntfy.', + min: 'Минимальный', + low: 'Низкий', + default: 'Обычный', + high: 'Высокий', + urgent: 'Срочный', + }, + cancel: 'Отмена', + save: 'Сохранить', + add: 'Добавить', + nameRequired: 'Укажите название', + fieldRequired: 'Поле «{{field}}» обязательно', + phoneNumber: 'Номер телефона', + apiKey: 'Ключ API', + serverUrl: 'URL сервера', + topic: 'Тема', + authToken: 'Токен авторизации', + userKey: 'Ключ пользователя', + appToken: 'Токен приложения', + priority: 'Приоритет', + botToken: 'Токен бота', + chatId: 'ID чата', + smtpServer: 'SMTP-сервер', + smtpPort: 'Порт SMTP', + security: 'Защита соединения', + authentication: 'Аутентификация', + username: 'Имя пользователя', + password: 'Пароль', + fromEmail: 'Адрес отправителя', + toEmail: 'Адрес получателя', + webhookUrl: 'URL вебхука', + payloadFormat: 'Формат данных', + authorization: 'Авторизация', + titleFieldName: 'Имя поля заголовка', + messageFieldName: 'Имя поля сообщения', + editTemplate: 'Изменить шаблон: {{name}}', + titleLabel: 'Заголовок', + bodyLabel: 'Текст', + titlePlaceholder: 'Заголовок уведомления...', + bodyPlaceholder: 'Текст уведомления...', + availableVariables: 'Доступные переменные', + clickToInsert: 'Нажмите, чтобы вставить в позицию курсора в тексте', + livePreview: 'Предварительный просмотр', + hide: 'Скрыть', + show: 'Показать', + loadingPreview: 'Загрузка предварительного просмотра...', + enterTemplateContent: 'Введите содержимое шаблона для предварительного просмотра', + titlePreview: 'Заголовок:', + bodyPreview: 'Текст:', + resetToDefault: 'Восстановить стандартный шаблон', + titleRequired: 'Укажите заголовок', + bodyRequired: 'Введите текст уведомления', + notificationLog: 'Журнал уведомлений', + showFailedOnly: 'Только неудачные', + last24Hours: 'Последние 24 часа', + last7Days: 'Последние 7 дней', + last30Days: 'Последние 30 дней', + last90Days: 'Последние 90 дней', + justNow: 'Только что', + noFailedNotifications: 'Неудачных уведомлений нет', + noNotificationsLogged: 'В журнале пока нет уведомлений', + unknownProvider: 'Неизвестный провайдер', + logTitle: 'Заголовок', + logMessage: 'Сообщение', + logError: 'Ошибка', + logProvider: 'Провайдер: {{type}}', + logTime: 'Время: {{time}}', + refresh: 'Обновить', + clearOld: 'Удалить старые', + statsSummary: 'За последние {{days}} дней:', + statsNotifications: 'уведомлений', + statsSent: 'отправлено: {{count}}', + statsFailed: 'ошибок: {{count}}', + eventTypes: { + print_start: 'Печать началась', + print_complete: 'Печать завершена', + print_failed: 'Ошибка печати', + print_stopped: 'Печать остановлена', + print_progress: 'Ход печати', + printer_offline: 'Принтер не в сети', + printer_error: 'Ошибка принтера', + filament_low: 'Заканчивается филамент', + maintenance_due: 'Требуется обслуживание', + test: 'Тест', + }, + userEmail: { + title: 'Уведомления', + emailNotifications: 'Уведомления по электронной почте', + emailNotificationsDesc: 'Получать письма о собственных заданиях печати. Для отправки используются системные параметры SMTP из раздела расширенной аутентификации.', + sendingTo: 'Уведомления будут отправляться на адрес', + noEmailWarning: 'Для вашей учётной записи не указан адрес электронной почты. Обратитесь к администратору.', + printJobNotifications: 'Уведомления о заданиях печати', + printJobNotificationsDesc: 'Выберите события, при которых будут отправляться письма о запущенных вами заданиях.', + printJobStarts: 'Запуск задания печати', + printJobStartsDesc: 'Уведомлять о начале вашего задания печати.', + printJobFinishes: 'Завершение задания печати', + printJobFinishesDesc: 'Уведомлять об успешном завершении вашего задания печати.', + printErrors: 'Ошибки печати', + printErrorsDesc: 'Уведомлять, если задание завершилось ошибкой или при печати возникла проблема.', + printJobStops: 'Остановка задания печати', + printJobStopsDesc: 'Уведомлять об отмене или остановке вашего задания печати.', + saveSuccess: 'Настройки уведомлений сохранены.', + saveError: 'Не удалось сохранить настройки уведомлений.', + }, + }, + richTextEditor: { + bold: 'Полужирный', + italic: 'Курсив', + underline: 'Подчёркивание', + bulletList: 'Маркированный список', + numberedList: 'Нумерованный список', + alignLeft: 'По левому краю', + alignCenter: 'По центру', + alignRight: 'По правому краю', + addLink: 'Добавить ссылку', + removeLink: 'Удалить ссылку', + }, + externalLinks: { + title: 'Ссылки на боковой панели', + sidebarLayout: 'Боковая панель', + sidebarLayoutDescription: 'Показывайте или скрывайте встроенные страницы, добавляйте внешние ссылки и перетаскивайте пункты, меняя порядок навигации.', + systemPages: 'Страницы Bambuddy', + externalLinks: 'Внешние ссылки', + visibleInSidebar: 'Показывается на боковой панели', + hiddenFromSidebar: 'Скрыто с боковой панели', + requiredInSidebar: 'Обязательный пункт боковой панели', + hidePage: 'Скрыть страницу', + showPage: 'Показать страницу', + settingsCannotBeHidden: 'Настройки нельзя скрыть', + noLinksConfigured: 'Внешние ссылки не настроены', + deleteLink: 'Удалить ссылку', + removeCustomIcon: 'Удалить пользовательский значок', + openInNewTab: 'Открывать в новой вкладке', + placeholders: { + linkName: 'Моя ссылка', + }, + }, + keyboardShortcuts: { + title: 'Горячие клавиши', + navigation: 'Навигация', + archivesSection: 'Архив', + kProfilesSection: 'K-профили', + generalSection: 'Общие', + shortcuts: { + goToPrinters: 'Перейти к принтерам', + goToArchives: 'Перейти в архив', + goToQueue: 'Перейти к очереди', + goToStats: 'Перейти к статистике', + goToProfiles: 'Перейти к облачным профилям', + goToSettings: 'Перейти к настройкам', + focusSearch: 'Перейти в строку поиска', + openUploadModal: 'Открыть окно загрузки', + clearSelection: 'Снять выделение / убрать фокус с поля', + contextMenu: 'Контекстное меню карточки', + refreshProfiles: 'Обновить профили', + newProfile: 'Новый профиль', + exitSelectionMode: 'Выйти из режима выделения', + showHelp: 'Показать эту справку', + }, + footer: 'Нажмите Esc или щёлкните снаружи, чтобы закрыть', + }, + notificationLog: { + title: 'Журнал уведомлений', + events: { + printStarted: 'Печать началась', + printComplete: 'Печать завершена', + printFailed: 'Ошибка печати', + printStopped: 'Печать остановлена', + progress: 'Ход выполнения', + printerOffline: 'Принтер не в сети', + printerError: 'Ошибка принтера', + lowFilament: 'Заканчивается филамент', + maintenanceDue: 'Требуется обслуживание', + test: 'Тест', + }, + timeAgo: { + justNow: 'Только что', + minutesAgo: '{{minutes}} мин назад', + hoursAgo: '{{hours}} ч назад', + }, + }, + restoreBackup: { + title: 'Восстановление резервной копии', + restoring: 'Восстановление...', + restoreComplete: 'Восстановление завершено', + restoreFailed: 'Ошибка восстановления', + importSettings: 'Импортировать настройки из файла резервной копии', + pleaseWait: 'Подождите, пока данные восстанавливаются', + clickToSelect: 'Нажмите, чтобы выбрать файл резервной копии (.json или .zip)', + howDuplicateHandling: 'Как обрабатываются совпадения:', + categories: { + printers: 'Принтеры', + smartPlugs: 'Умные розетки', + notificationProviders: 'Провайдеры уведомлений', + filaments: 'Филаменты', + archives: 'Архив', + pendingUploads: 'Ожидающие загрузки', + settingsTemplates: 'Настройки и шаблоны', + }, + matchingInfo: { + printers: 'сопоставляются по серийному номеру', + smartPlugs: 'сопоставляются по IP-адресу', + notificationProviders: 'сопоставляются по названию', + filaments: 'сопоставляются по названию, типу и бренду', + archives: 'сопоставляются по хешу содержимого', + pendingUploads: 'сопоставляются по имени файла', + settingsTemplates: 'всегда перезаписываются', + }, + replaceExisting: 'Заменить существующие данные', + keepExisting: 'Сохранить существующие данные', + replaceDescription: 'Перезаписать уже существующие элементы данными из резервной копии', + keepDescription: 'Восстановить только отсутствующие элементы', + caution: 'Внимание:', + cautionText: 'При перезаписи текущая конфигурация будет заменена данными из резервной копии. В целях безопасности коды доступа к принтерам никогда не перезаписываются.', + itemsRestored: 'Восстановлено элементов', + itemsSkipped: 'Пропущено элементов', + restored: 'Восстановлено', + skipped: 'Пропущено (уже существует)', + filesLabel: 'Файлы (3MF, миниатюры и т. п.)', + newApiKeysGenerated: 'Созданы новые ключи API', + newApiKeysWarning: 'Эти ключи показываются только один раз. Скопируйте их сейчас!', + processingBackup: 'Обработка резервной копии...', + noDataFound: 'В резервной копии не найдено данных для восстановления.', + failedToRestore: 'Не удалось восстановить резервную копию. Проверьте формат файла.', + }, + backupExport: { + title: 'Экспорт резервной копии', + selectData: 'Выберите данные для включения', + selectAll: 'Выбрать всё', + selectNone: 'Снять выделение', + categoryDescriptions: { + settings: 'Язык, тема и настройки обновлений', + notifications: 'ntfy, Pushover, Discord и другие', + templates: 'Пользовательские шаблоны сообщений', + smartPlugs: 'Конфигурация розеток Tasmota', + externalLinks: 'Ссылки на внешние сервисы в боковой панели', + printers: 'Сведения о принтерах (без кодов доступа)', + plateDetection: 'Эталонные изображения пустых пластин', + filaments: 'Типы и стоимость филамента', + maintenance: 'Пользовательские графики обслуживания', + archives: 'Все данные печати и файлы (3MF, миниатюры, фотографии)', + projects: 'Проекты, позиции спецификаций и вложения', + pendingUploads: 'Загрузки виртуальных принтеров, ожидающие проверки', + apiKeys: 'Ключи API вебхуков (при импорте создаются новые)', + }, + requiresPrinters: 'Необходимо выбрать раздел «Принтеры»', + zipFileWarning: 'Будет создан ZIP-файл.', + zipFileDescription: 'В него войдут все файлы 3MF, миниатюры, таймлапсы и фотографии. Операция может занять некоторое время, а файл — получиться большим.', + includeAccessCodes: 'Включить коды доступа', + includeAccessCodesDescription: 'Для переноса на другой компьютер', + includeAccessCodesWarning: 'Коды доступа попадут в файл открытым текстом. Храните резервную копию в безопасном месте!', + categoriesSelected: 'Выбрано категорий: {{selectedCount}}', + }, + pendingUploads: { + placeholders: { + notes: 'Добавьте примечания об этой печати...', + }, + discardUpload: 'Отклонить загрузку', + archiveAllUploads: 'Добавить все загрузки в архив', + discardAllUploads: 'Отклонить все загрузки', + archive: 'В архив', + timeAgo: { + justNow: 'Только что', + minutesAgo: '{{minutes}} мин назад', + hoursAgo: '{{hours}} ч назад', + daysAgo: '{{days}} дн. назад', + }, + }, + apiBrowser: { + placeholders: { + requestBody: 'Тело запроса JSON...', + searchEndpoints: 'Поиск конечных точек...', + }, + }, + configureAmsSlot: { + title: 'Настройка слота AMS', + slotConfigured: 'Слот настроен!', + configuringSlot: 'Настраивается слот:', + slotLabel: '{{ams}}, слот {{slot}}', + searchPresets: 'Поиск профилей...', + colorPlaceholder: 'Название или HEX-код цвета (например: brown, FF8800)', + clearCustomColor: 'Очистить пользовательский цвет', + noCloudPresets: 'Облачных профилей нет. Войдите в Bambu Cloud для синхронизации.', + noPresetsAvailable: 'Нет доступных профилей. Войдите в Bambu Cloud или импортируйте локальные профили.', + noMatchingPresets: 'Подходящие профили не найдены.', + custom: 'Пользовательский', + builtin: 'Встроенный', + orcaCloud: 'Orca Cloud', + bambuCloud: 'Bambu Cloud', + settingsSentToPrinter: 'Настройки отправлены на принтер', + filamentProfile: 'Профиль филамента', + kProfileLabel: 'K-профиль (Pressure Advance)', + filteringFor: 'Фильтр по материалу: {{material}}', + noKProfile: 'Без K-профиля (стандартное значение 0,020)', + noMatchingKProfiles: 'Подходящие K-профили не найдены. Будет использовано стандартное значение K=0,020.', + selectFilamentFirst: 'Сначала выберите профиль филамента', + kFromCalibration: 'K={{value}} из калибровки принтера', + customColorLabel: 'Пользовательский цвет (необязательно)', + presetColors: 'Цвета {{name}}:', + showLessColors: 'Показать меньше цветов', + showMoreColors: 'Показать больше цветов', + clear: 'Очистить', + hexLabel: 'HEX: #{{hex}}', + resetting: 'Сброс...', + resetSlot: 'Сбросить слот', + cancel: 'Отмена', + configuring: 'Настройка...', + configureSlot: 'Настроить слот', + }, + githubBackup: { + title: 'Резервное копирование в Git', + history: 'История', + downloadBackup: 'Скачать резервную копию', + restoreBackup: 'Восстановить резервную копию', + noBackupsYet: 'Резервных копий пока нет', + }, + emailSettings: { + placeholders: { + fromName: 'BamBuddy', + }, + }, + tagManagement: { + searchTags: 'Поиск меток...', + renameTag: 'Переименовать метку', + deleteTag: 'Удалить метку', + }, + notificationTemplates: { + placeholders: { + title: 'Заголовок уведомления...', + body: 'Текст уведомления...', + }, + }, + batchTag: { + placeholders: { + newTag: 'Введите новую метку...', + }, + }, + photoGallery: { + deletePhoto: 'Удалить фотографию', + }, + filamentHoverCard: { + copySpoolUuid: 'Скопировать UUID катушки', + }, + kProfilesView: { + hasNote: 'Есть примечание', + copyProfile: 'Копировать профиль', + }, + layout: { + openMenu: 'Открыть меню', + noPermissionSystemInfo: 'У вас нет разрешения на просмотр системной информации', + }, + dashboard: { + dragToReorder: 'Перетащите, чтобы изменить порядок', + hideWidget: 'Скрыть виджет', + }, + notificationProviderCard: { + deleteNotificationProvider: 'Удалить провайдера уведомлений', + }, + fileManagerModal: { + closeFileManager: 'Закрыть файловый менеджер', + sortFiles: 'Сортировать файлы', + goToParentFolder: 'Перейти в родительскую папку', + threeView: 'Просмотр 3D', + }, + embeddedCameraViewer: { + refreshStream: 'Обновить поток', + close: 'Закрыть', + zoomOut: 'Уменьшить', + resetZoom: 'Сбросить масштаб', + zoomIn: 'Увеличить', + dragToResize: 'Перетащите, чтобы изменить размер', + }, + timelapseViewer: { + skipBack5s: 'Назад на 5 с', + skipForward5s: 'Вперёд на 5 с', + }, + notificationProviders: { + descriptions: { + email: 'Уведомления по электронной почте через SMTP', + telegram: 'Уведомления через Telegram-бота', + discord: 'Отправка в канал Discord через вебхук', + ntfy: 'Бесплатные push-уведомления с возможностью самостоятельного размещения сервера', + pushover: 'Простые и надёжные push-уведомления', + callmebot: 'Бесплатные уведомления WhatsApp через CallMeBot', + webhook: 'Обычный HTTP POST на любой URL', + }, + }, + logViewer: { + searchPlaceholder: 'Поиск по сообщению или имени логгера...', + noLogEntries: 'Записи журнала не найдены', + }, + switchbarPopover: { + noSwitchesInSwitchbar: 'На панели переключателей нет устройств', + }, + projectPageModal: { + placeholders: { + title: 'Название', + designer: 'Автор', + license: 'Лицензия', + description: 'Введите описание...', + profileTitle: 'Название профиля', + profileDescription: 'Описание профиля...', + }, + }, + spoolmanSettings: { + }, + time: { + unknown: '—', + waiting: 'Ожидание', + justNow: 'Только что', + now: 'Сейчас', + minsAgo: '{{count}} мин назад', + inMins: 'через {{count}} мин', + hoursAgo: '{{count}} ч назад', + inHours: 'через {{count}} ч', + daysAgo: '{{count}} дн. назад', + inDays: 'через {{count}} дн.', + }, + setup: { + title: 'Настройка Bambuddy', + subtitle: 'Настройте аутентификацию для этого экземпляра Bambuddy', + enableAuth: 'Включить аутентификацию', + adminAccount: 'Учётная запись администратора', + adminAccountDesc: 'Если администраторы уже существуют, аутентификация будет включена с использованием существующих учётных записей. Оставьте поля пустыми или введите данные для создания нового администратора.', + adminUsername: 'Имя администратора', + adminPassword: 'Пароль администратора', + optionalIfAdminExists: '(необязательно, если администратор уже существует)', + adminUsernamePlaceholder: 'Введите имя администратора (необязательно)', + adminPasswordPlaceholder: 'Введите пароль администратора (необязательно)', + confirmPassword: 'Подтвердите пароль', + confirmPasswordPlaceholder: 'Повторите пароль администратора', + settingUp: 'Настройка...', + completeSetup: 'Завершить настройку', + toast: { + authEnabledAdminCreated: 'Аутентификация включена, администратор создан', + authEnabledExistingAdmins: 'Аутентификация включена для существующих администраторов', + setupCompleted: 'Настройка завершена', + enterBothCredentials: 'Введите имя и пароль администратора либо оставьте оба поля пустыми', + passwordsDoNotMatch: 'Пароли не совпадают', + passwordTooShort: 'Пароль должен содержать не менее 6 символов', + }, + }, + failureDetection: { + title: 'Обнаружение сбоев с помощью ИИ', + description: 'Контролируйте печать через собственный сервер Obico ML API и автоматически реагируйте на обнаруженные сбои.', + mlUrl: 'URL Obico ML API', + mlUrlHint: 'Базовый URL собственного контейнера Obico ml_api, например http://192.168.1.10:3333.', + test: 'Проверить', + testSuccess: 'ML API доступен и работает.', + testFailed: 'Не удалось подключиться к ML API.', + sensitivity: 'Чувствительность', + sensitivityLow: 'Низкая (меньше ложных срабатываний)', + sensitivityMedium: 'Средняя (сбалансированная)', + sensitivityHigh: 'Высокая (раннее обнаружение, больше ложных срабатываний)', + sensitivityHint: 'Определяет пороги уверенности, при которых создаются предупреждения и фиксируются сбои.', + action: 'Действие при обнаружении сбоя', + actionNotify: 'Только уведомить', + actionPause: 'Приостановить печать', + actionPauseOff: 'Приостановить печать и отключить питание', + pollInterval: 'Интервал проверки (секунды)', + pollIntervalHint: 'Как часто проверять каждый принтер во время печати. Минимум 5 с, максимум 120 с.', + externalUrlMissing: 'Внешний URL не задан.', + externalUrlHint: 'ML API получает снимок камеры по URL. Укажите внешний URL в общих настройках, чтобы контейнер ML API мог обращаться к Bambuddy.', + perPrinterTitle: 'Контролируемые принтеры', + perPrinterHint: 'Выберите принтеры, за которыми будет следить служба обнаружения.', + monitorAll: 'Контролировать все подключённые принтеры', + statusTitle: 'Состояние', + serviceRunning: 'Служба работает', + thresholds: 'Низкий / высокий порог', + activePrinters: 'Активные задания', + noActivePrints: 'Сейчас ничего не печатается.', + historyTitle: 'Последние обнаружения', + noHistory: 'Обнаружений пока нет.', + }, + cameraTokens: { + title: 'Токены API камеры', + navTitle: 'Токены API камеры', + description: 'Долгоживущие токены для встраивания видеопотока в Home Assistant, Frigate, киоски и другие системы, которым нужен постоянный URL. Каждый токен даёт доступ только к потоку камеры и может быть отозван в любой момент.', + loading: 'Загрузка...', + confirmRevoke: { + title: 'Отозвать этот токен?', + body: 'Все устройства, использующие «{{name}}», немедленно потеряют доступ. Отменить это действие нельзя.', + cancel: 'Отмена', + confirm: 'Отозвать', + }, + create: { + title: 'Создать токен', + nameLabel: 'Название токена', + namePlaceholder: 'Например, Home Assistant', + daysLabel: 'Срок действия, дней', + submit: 'Создать', + hint: 'Максимальный срок действия — 365 дней. Значение токена показывается только один раз при создании — скопируйте его сейчас.', + }, + created: { + title: 'Токен создан — скопируйте его сейчас', + warning: 'Это единственный раз, когда токен отображается. После закрытия окна посмотреть его снова будет невозможно.', + copy: 'Копировать', + dismiss: 'Я сохранил токен', + }, + list: { + myTitle: 'Мои токены', + allTitle: 'Все пользователи (режим администратора)', + empty: 'Токенов пока нет.', + name: 'Название', + owner: 'Владелец', + prefix: 'Префикс', + created: 'Создан', + expires: 'Истекает', + lastUsed: 'Последнее использование', + revoke: 'Отозвать', + expired: 'Истёк', + }, + toast: { + created: 'Токен создан', + createFailed: 'Не удалось создать токен', + revoked: 'Токен отозван', + revokeFailed: 'Не удалось отозвать токен', + loadFailed: 'Не удалось загрузить токены', + copied: 'Скопировано в буфер обмена', + copyFailed: 'Не удалось скопировать — выделите и скопируйте вручную', + }, + }, + makerworld: { + title: 'MakerWorld', + description: 'Вставьте URL модели MakerWorld, чтобы импортировать и напечатать её прямо из Bambuddy — без перехода в приложение Bambu Handy.', + pasteUrlHeader: 'Импорт из MakerWorld', + pasteUrlPlaceholder: 'https://makerworld.com/en/models/… или любая ссылка MakerWorld', + resolveButton: 'Получить данные', + signInRequiredTitle: 'Для загрузки требуется вход в Bambu Cloud', + signInRequiredBody: 'Просматривать сведения о модели можно анонимно, но для загрузки файлов 3MF MakerWorld требует учётную запись Bambu Cloud.', + openCloudSettings: 'Открыть настройки облака', + untitledModel: 'Модель без названия', + byCreator: 'Автор: {{name}}', + downloadsCount: 'Загрузок: {{count}}', + licensePrefix: 'Лицензия', + alreadyImported: 'Уже в библиотеке', + openOnMakerworld: 'Открыть на MakerWorld', + alreadyInLibrary: 'Эта модель уже есть в библиотеке — найдите её в разделе «Файлы → MakerWorld».', + importSuccess: 'Импортирован файл {{filename}} — сохранён в «Файлы → MakerWorld».', + platesHeader: 'Пластины ({{count}})', + plateDefaultName: 'Пластина {{n}}', + materialCount: 'Филаментов: {{count}}', + amsRequired: 'Требуется AMS', + slicedFor: 'Нарезано для {{printer}}', + alsoCompatible: 'Также отмечено как совместимое: {{printers}}', + importToLibrary: 'Сохранить', + sliceIn: 'Сохранить и нарезать в {{slicer}}', + disclaimer: 'Интеграция с MakerWorld использует документированные сообществом конечные точки API. Bambuddy не связан с MakerWorld или Bambu Lab и не одобрен ими.', + lastImportSuccess: 'Импортировано в библиотеку', + lastImportAlreadyInLibrary: 'Уже в библиотеке', + viewInLibrary: 'Открыть в файловом менеджере', + openInBambuStudio: 'Открыть в Bambu Studio', + openInOrcaSlicer: 'Открыть в OrcaSlicer', + importTo: 'Импортировать в файловый менеджер', + recentImportsHeader: 'Недавние импорты', + phaseResolving: 'Получение данных', + phaseDownloading: 'Загрузка', + folderAuto: 'MakerWorld (по умолчанию)', + importAll: 'Импортировать всё', + importAllProgress: 'Импорт {{current}} из {{total}}', + openGallery: 'Открыть галерею изображений', + galleryPrev: 'Предыдущее изображение', + galleryNext: 'Следующее изображение', + deleteImport: 'Удалить из библиотеки', + importDeleting: 'Удаление…', + importDeleted: 'Удалено из библиотеки', + confirmDelete: 'Удалить {{filename}} из библиотеки? Локальный файл будет удалён, но пластину можно снова импортировать из MakerWorld.', + errors: { + resolveFailed: 'Не удалось обработать эту ссылку MakerWorld.', + downloadFailed: 'Ошибка загрузки. Повторите попытку.', + deleteFailed: 'Не удалось удалить файл из библиотеки.', + }, + }, + diagnostic: { + modalTitle: 'Диагностика подключения — {{name}}', + running: 'Выполняется диагностика...', + runningElapsed: 'Выполняется диагностика... ({{elapsed}} с)', + waitingForReportHint: 'Ожидание публикации отчёта о состоянии принтера — это может занять до {{max}} секунд.', + runFailed: 'Не удалось выполнить диагностику: {{error}}', + retry: 'Запустить снова', + runButton: 'Запустить диагностику', + sectionTitle: 'Диагностика подключения', + sectionDescription: 'Проверьте, почему принтер не подключается или не печатает: доступность портов, режим разработчика LAN, сетевой режим Docker и учётные данные.', + noPrinters: 'Принтеры не настроены.', + overall: { + ok: 'Проблем не обнаружено — подключение к принтеру исправно.', + warnings: 'Принтер должен работать, но некоторые пункты требуют внимания.', + problems: 'Обнаружены проблемы, объясняющие, почему принтер не подключается или не печатает.', + }, + check: { + port_mqtt: { + title: 'Порт управления (MQTT 8883)', + pass: 'Доступен — принтер принимает управляющие подключения.', + fail: 'Порт 8883 недоступен. Принтер выключен, имеет другой IP-адрес либо подключение блокирует межсетевой экран. Проверьте IP-адрес принтера и доступность порта 8883.', + }, + port_ftps: { + title: 'Порт передачи файлов (FTPS 990)', + pass: 'Доступен — отправка файлов печати будет работать.', + warn: 'Порт 990 недоступен. Мониторинг может работать, но отправка заданий на принтер завершится ошибкой. Убедитесь, что порт 990 не заблокирован.', + }, + external_storage: { + title: 'Сохранять отправленные файлы во внешнем хранилище (шаг 4 установки)', + pass: 'Принтер сообщает, что параметр включён: отправленные файлы будут сохраняться на SD-карте, а в архиве появятся миниатюры и метаданные слайсера.', + fail: 'Принтер сообщает, что параметр выключен. Включите «Сохранять отправленные файлы во внешнем хранилище»: в новых прошивках (P2S 01.02 / Bambu Studio 2.6+) переключатель находится в настройках печати принтера, в старых — на вкладке «Устройство» Bambu Studio / OrcaSlicer. Без этого у всех архивных заданий не будет миниатюр и метаданных слайсера.', + skip: 'Не проверено — требуется активное подключение MQTT. В старых версиях слайсеров этот параметр существует только в слайсере и принтер его не сообщает, поэтому проверка может пройти даже при выключенном параметре. Проверьте шаг 4 установки вручную.', + }, + port_rtsps: { + title: 'Порт камеры ({{protocol}} {{port}})', + pass: 'Доступен — видеопоток камеры будет работать.', + warn: 'Порт {{port}} недоступен. Просмотр камеры в реальном времени работать не будет. На печать это не влияет.', + }, + network_mode: { + title: 'Сетевой режим Docker', + pass: 'Используется сетевой режим host.', + warn: 'Bambuddy запущен в Docker с сетью bridge. Для обнаружения принтеров и виртуального принтера требуется режим host — пересоздайте контейнер с параметром «network_mode: host».', + skip: 'Bambuddy запущен не в Docker — проверка неприменима.', + }, + subnet: { + title: 'Подсеть', + pass: 'Принтер и Bambuddy находятся в одной подсети.', + warn: 'Принтер ({{printer_ip}}) и Bambuddy ({{host_ip}}) находятся в разных подсетях. Без настроенной маршрутизации между подсетями они могут быть недоступны друг для друга.', + skip: 'Не удалось определить подсеть — проверка пропущена.', + }, + mqtt_auth: { + title: 'Учётные данные принтера', + pass: 'Принтер принял подключение.', + fail: 'Принтер доступен, но отклонил подключение. Скорее всего, неверны код доступа или серийный номер. Код доступа изменяется при каждом переключении режима разработчика — снова скопируйте его с экрана принтера.', + skip: 'Не проверено — принтер недоступен.', + }, + developer_mode: { + title: 'Режим разработчика LAN', + pass: 'Режим разработчика включён.', + fail: 'Режим разработчика на принтере ВЫКЛЮЧЕН. Включите его в настройках LAN принтера и подтвердите кнопкой OK. Без него задания печати не запускаются.', + skip: 'Не удалось проверить — требуется активное подключение к принтеру.', + }, + printer_publishing: { + title: 'Принтер публикует состояние', + pass: 'Принтер публикует обновления состояния — AMS, филаменты и K-профили будут корректно передаваться в слайсер.', + fail: 'MQTT-брокер принял подключение, но принтер не опубликовал ни одного отчёта о состоянии. Почти всегда причина в неверном регистре или ошибке в серийном номере: тема device//report чувствительна к регистру. Сверьте серийный номер в настройках принтера с номером на его экране.', + skip: 'Не удалось проверить — требуется активное подключение к принтеру.', + }, + }, + }, + libraryTrash: { + title: 'Корзина', + headerButton: 'Корзина', + headerTooltip: 'Просмотреть файлы, перемещённые в корзину', + backToFiles: 'Вернуться к файлам', + subtitleAdmin: 'Удалённые файлы хранятся здесь {{days}} дней, затем удаляются автоматически. Показаны файлы всех пользователей.', + subtitleUser: 'Удалённые файлы хранятся здесь {{days}} дней, затем удаляются автоматически.', + loading: 'Загрузка корзины…', + loadError: 'Не удалось загрузить корзину.', + empty: 'Корзина пуста.', + summary: '{{count}} файлов · {{size}}', + emptyTrash: 'Очистить корзину', + restore: 'Восстановить', + purgeNow: 'Удалить сейчас', + autoPurgeIn: 'Автоудаление через {{when}}', + days: 'дней', + retentionLabel: 'Автоудаление через', + selectAll: 'Выбрать всё', + selectOne: 'Выбрать {{filename}}', + selectionCount: 'Выбрано: {{count}}', + bulkRestore: 'Восстановить выбранные', + bulkPurge: 'Удалить выбранные', + col: { + filename: 'Файл', + folder: 'Папка', + size: 'Размер', + deleted: 'Перемещён в корзину', + autoPurge: 'Автоудаление', + owner: 'Владелец', + actions: 'Действия', + }, + confirm: { + purgeTitle: 'Удалить навсегда?', + purgeBody: 'Файл {{filename}} будет удалён с диска без возможности восстановления.', + emptyTitle: 'Очистить корзину?', + emptyBody: 'Все файлы ({{count}}) будут удалены с диска. Отменить это действие нельзя.', + bulkPurgeTitle: 'Удалить выбранные файлы навсегда?', + bulkPurgeBody: 'Выбранные файлы ({{count}}) будут удалены с диска без возможности восстановления.', + cta: 'Удалить навсегда', + }, + toast: { + restored: 'Файл восстановлен.', + restoreFailed: 'Не удалось восстановить файл.', + purged: 'Файл удалён навсегда.', + purgeFailed: 'Не удалось удалить файл.', + emptied: 'Из корзины удалено файлов: {{count}}.', + emptyFailed: 'Не удалось очистить корзину.', + retentionSaved: 'Срок автоудаления: {{days}} дней.', + retentionFailed: 'Не удалось сохранить срок хранения.', + bulkRestored: 'Восстановлено файлов: {{count}}.', + bulkPurged: 'Удалено файлов: {{count}}.', + }, + }, + bugReport: { + title: 'Сообщить об ошибке', + description: 'Описание', + descriptionPlaceholder: 'Что пошло не так? Опишите проблему...', + email: 'Электронная почта (необязательно)', + emailPlaceholder: 'your@email.com', + emailPrivacy: 'Указанный адрес будет добавлен в сворачиваемый раздел задачи GitHub, чтобы сопровождающий мог с вами связаться.', + screenshot: 'Снимок экрана', + uploadOrPaste: 'Загрузите, вставьте или перетащите изображение', + dataCollectedSummary: 'Какие данные включаются в отчёт?', + dataIncluded: 'Включаются:', + dataIncludedList: 'Версия приложения, ОС, архитектура, версия Python, статистика базы данных (только количества), модели принтеров, количество сопел, версии прошивок, состояние подключений, состояние интеграций (Spoolman, MQTT, HA), неконфиденциальные настройки, количество сетевых интерфейсов, сведения о Docker и версии зависимостей.', + dataNeverIncluded: 'Никогда не включаются:', + dataNeverIncludedList: 'Имена принтеров, серийные номера, коды доступа, пароли, IP-адреса, адреса электронной почты, ключи API, токены, URL вебхуков, имена хостов и пользователей.', + submit: 'Отправить', + startLogging: 'Начать отладочную запись', + stepEnableLogging: 'Отладочная запись включена', + stepReproduce: 'Теперь воспроизведите проблему', + stepStopLogging: 'Остановить и отправить отчёт', + stopAndSubmit: 'Остановить и отправить', + maxDuration: 'Автоматическая остановка через {{minutes}} мин', + stoppingLogs: 'Сбор журналов и отправка...', + submitting: 'Отправка отчёта об ошибке...', + submittingStepConnection: 'Проверка подключений к принтерам', + submittingStepVirtualPrinters: 'Проверка настройки виртуальных принтеров', + submittingStepLogScan: 'Поиск известных проблем в последних журналах', + submittingStepSubmit: 'Отправка отчёта в GitHub', + submitSuccess: 'Отчёт об ошибке успешно отправлен!', + submitFailed: 'Не удалось отправить отчёт об ошибке', + diagnosticChecking: 'Проверка подключений к принтерам...', + diagnosticHealthy: 'Проверка подключения пройдена — проблем с принтерами не обнаружено.', + diagnosticSummary: 'Проблемы с подключением обнаружены у {{problems}} из {{total}} принтеров', + diagnosticIntro: 'У одного или нескольких принтеров есть проблема подключения, которая может быть причиной сбоя. Разверните сведения о принтере ниже и посмотрите способ исправления — возможно, отчёт об ошибке не потребуется. При необходимости его всё равно можно отправить ниже.', + logHealthSummary: 'В журналах найдены известные проблемы', + logHealthIntro: 'Последние записи журнала совпадают с известными проблемами. Посмотрите способы исправления ниже — возможно, отчёт об ошибке не потребуется. При необходимости его всё равно можно отправить.', + thankYou: 'Спасибо!', + submitted: 'Отчёт об ошибке отправлен.', + viewIssue: 'Открыть задачу', + unexpectedError: 'Произошла непредвиденная ошибка', + }, + forecast: { + title: 'Прогноз', + noSpools: 'Активные катушки не найдены. Добавьте катушки в учёт, чтобы увидеть прогноз.', + noUsageData: 'Нет данных о расходе — невозможно спрогнозировать остатки.', + sku: 'Артикул', + material: 'Материал', + stock: 'Запас', + dailyRate: 'Расход', + daysLeft: 'Осталось дней', + emptyBy: 'Закончится к', + reorderBy: 'Заказать до', + actions: 'Действия', + trend: 'Тренд', + estimated: 'Оценка', + noData: 'Нет данных', + timeframe: 'Период', + chartTitle: 'Прогноз запаса — 5 основных материалов', + dashedLinesROP: 'Пунктирные линии — точки заказа', + stockLevel: 'Уровень запаса', + reorderPoint: 'Точка заказа', + safetyMargin: 'Страховой запас', + trendLegend: 'Тренд (по истории, уровень обслуживания 95%)', + estimatedLegend: 'Оценка (по изменению массы)', + noDataLegend: 'Нет данных', + ropLabel: 'ТЗ', + ssLabel: 'СЗ', + safetyStockLegend: 'Страховой запас', + stockArrivalLegend: 'Поступление', + stockoutLegend: 'Исчерпание запаса', + alertCount_one: '{{count}} предупреждение', + alertCount_other: '{{count}} предупреждений', + order: 'Заказать', + save: 'Сохранить', + cancel: 'Отмена', + settingsSaved: 'Настройки сохранены', + failedSaveSettings: 'Не удалось сохранить настройки', + globalLeadTimeSaved: 'Общий срок поставки сохранён', + globalLeadTime: 'Общий срок поставки', + globalLeadTimeHint: 'Минимальный общий срок поставки, используемый при расчёте точки заказа для всех артикулов', + skuLeadTimeOverride: 'Переопределение срока поставки', + skuLeadTimeHint: '0 — использовать общий срок поставки. Значение больше 0 переопределяет его для этого артикула.', + safetyMarginLabel: 'Страховой запас', + effectiveLeadTime: 'Фактический срок поставки', + effectiveLeadTimeHint: 'макс. (общий {{global}} дн., для артикула {{sku}} дн.)', + reorderPointHint: 'средний расход × срок поставки + страховой запас — заказывайте, когда остаток достигнет этого уровня', + safetyMarginHint: 'Статистический страховой запас (z=1,65 × σ × √LT) плюс заданный пользователем резерв', + safetyMarginHintDays: 'Резерв поверх статистического страхового запаса.{{approx}}', + safetyMarginHintDaysApprox: ' ≈ {{g}} г при текущем расходе.', + safetyMarginHintG: 'Фиксированный весовой резерв поверх статистического страхового запаса.{{approx}}', + safetyMarginHintGApprox: ' ≈ {{days}} дн. при текущем расходе.', + individualSpools: 'Отдельные катушки', + labelWeight: 'Метка', + spoolCount_one: '{{count}} катушка', + spoolCount_other: '{{count}} катушек', + stockBreakRisk: 'Риск исчерпания запаса', + stockBreakDetail: 'Осталось {{days}} дн., срок поставки {{lt}} дн.', + stockBreakBefore: 'Запас закончится до пополнения', + reorderNow: 'Заказать сейчас', + reorderTriggerPassed: 'Дата заказа {{date}} уже прошла.', + shoppingList: 'Список покупок', + shoppingListItems_one: '({{count}} позиция)', + shoppingListItems_other: '({{count}} позиций)', + shoppingListEmpty: 'Список покупок пуст. Нажмите значок корзины в нужной строке, чтобы добавить позицию.', + addToCart: 'Добавить в список покупок', + alertsSnoozed: 'Отключить предупреждения для артикула', + alertsEnabled: 'Включить предупреждения для артикула', + addedToCart: 'Добавлено в список покупок', + failedAddItem: 'Не удалось добавить позицию', + listView: 'Список', + logisticsView: 'Логистика', + qty: 'Кол-во', + weight: 'Масса', + leadTime: 'Срок поставки', + expectedRestock: 'Ожидаемое пополнение', + status: 'Состояние', + note: 'Примечание', + pending: 'Ожидается', + purchased: 'Куплено', + received: 'Получено', + markPurchased: 'Отметить как купленное', + markReceived: 'Отметить как полученное — катушки будут добавлены в запас', + resetToPending: 'Вернуть в ожидание', + remove: 'Удалить', + clearAll: 'Очистить всё', + downloadCsv: 'CSV', + addToCartTitle: 'Добавить в список покупок', + byQuantity: 'По количеству', + byDuration: 'По сроку', + numberOfSpools: 'Количество катушек', + lastHowManyDays: 'На сколько дней должно хватить?', + noUsageQty: 'Нет данных о расходе — количество установлено равным 1.', + noteOptional: 'Примечание (необязательно)', + notePlaceholder: 'например, для проекта X, срочно…', + addNSpools_one: 'Добавить {{count}} катушку', + addNSpools_other: 'Добавить {{count}} катушек', + onArrival: 'После поступления', + stockBreakIn: 'Запас закончится через {{days}} дн.', + stockRunsOutBefore: 'Запас закончится раньше, чем истекут {{lt}} дн. срока поставки.', + atRate: 'При расходе {{rate}} г/день требуется', + moreSpools_one: 'ещё {{count}} катушка', + moreSpools_other: 'ещё {{count}} катушек', + bridgeGap: 'чтобы перекрыть дефицит.', + noReadAccess: 'У вас нет прав на просмотр прогноза запасов.', + noWriteAccess: 'У вас нет прав на изменение настроек прогноза.', + }, + kProfiles: { + title: 'K-профили', + noPrintersConfigured: 'Принтеры не настроены', + addPrinterInSettings: 'Добавьте принтер в настройках, чтобы управлять K-профилями', + noActivePrinters: 'Нет активных принтеров', + enablePrinterConnection: 'Включите подключение к принтеру, чтобы просматривать его K-профили', + loadingProfiles: 'Загрузка K-профилей...', + printerOffline: 'Принтер не в сети', + printerOfflineDesc: 'Выбранный принтер не подключён. Включите его, чтобы просмотреть K-профили.', + noMatchingProfiles: 'Подходящие профили не найдены', + noMatchingProfilesDesc: 'Ни один профиль не соответствует условиям поиска', + noKProfiles: 'K-профили отсутствуют', + noKProfilesDesc: 'Для сопла {{diameter}} мм не найдены профили Pressure Advance', + createFirstProfile: 'Создать первый профиль', + printer: 'Принтер', + nozzle: 'Сопло', + refresh: 'Обновить', + addProfile: 'Добавить профиль', + export: 'Экспорт', + import: 'Импорт', + select: 'Выбрать', + selectAll: 'Выбрать все', + delete: 'Удалить', + searchPlaceholder: 'Поиск по названию или филаменту...', + allExtruders: 'Все экструдеры', + leftOnly: 'Только левый', + rightOnly: 'Только правый', + allFlow: 'Любой тип потока', + hfOnly: 'Только HF', + sOnly: 'Только S', + sortName: 'Сортировка: название', + sortKValue: 'Сортировка: K-значение', + sortFilament: 'Сортировка: филамент', + leftExtruder: 'Левый экструдер', + rightExtruder: 'Правый экструдер', + modal: { + addTitle: 'Добавить K-профиль', + editTitle: 'Изменить K-профиль', + profileName: 'Название профиля', + profileNamePlaceholder: 'Мой профиль PLA', + kValue: 'K-значение', + kValuePlaceholder: '0.020', + kValueHelp: 'Типичный диапазон: 0,01–0,06 для PLA, 0,02–0,10 для PETG', + filament: 'Филамент', + selectFilament: 'Выберите филамент...', + noFilamentsHelp: 'Филаменты не найдены. Сначала создайте K-профиль в Bambu Studio.', + flowType: 'Тип потока', + highFlow: 'Высокопоточный', + standard: 'Стандартный', + nozzleSize: 'Диаметр сопла', + extruder: 'Экструдер', + extruders: 'Экструдеры', + left: 'Левый', + right: 'Правый', + notes: 'Заметки (хранятся локально)', + notesPlaceholder: 'Добавьте заметки об этом профиле...', + notesHelp: 'Заметки сохраняются в Bambuddy, а не на принтере', + syncing: 'Синхронизация с принтером...', + savingExtruder: 'Сохранение в экструдер {{current}}/{{total}}...', + pleaseWait: 'Подождите', + }, + deleteConfirm: { + title: 'Удалить профиль', + cannotUndo: 'Это действие нельзя отменить', + message: 'Удалить профиль «{{name}}» с принтера?', + }, + bulkDelete: { + title: 'Удалить профили', + cannotUndo: 'Это действие нельзя отменить', + message: 'Удалить с принтера выбранные профили ({{count}})?', + }, + toast: { + profileSaved: 'K-профиль сохранён', + profilesSaved: 'K-профиль сохранён для {{count}} экструдеров', + selectAtLeastOneExtruder: 'Выберите хотя бы один экструдер', + profileDeleted: 'K-профиль удалён', + profilesDeleted: 'Удалено профилей: {{count}}', + exportedProfiles: 'Экспортировано профилей: {{count}}', + importedProfiles: 'Импортировано {{count}} из {{total}} профилей', + noProfilesToExport: 'Нет профилей для экспорта', + invalidFileFormat: 'Недопустимый формат файла', + failedToParseImport: 'Не удалось разобрать файл импорта', + failedToSaveBatch: 'Не удалось сохранить K-профили', + noteSaved: 'Заметка сохранена', + failedToSaveNote: 'Не удалось сохранить заметку', + }, + permission: { + noRead: 'У вас нет прав на обновление профилей', + noCreate: 'У вас нет прав на добавление профилей', + noUpdate: 'У вас нет прав на изменение K-профилей', + noDelete: 'У вас нет прав на удаление K-профилей', + noExport: 'У вас нет прав на экспорт профилей', + noImport: 'У вас нет прав на импорт профилей', + }, + }, + spoolbuddy: { + nav: { + dashboard: 'Панель', + ams: 'AMS', + inventory: 'Катушки', + writeTag: 'Запись метки', + settings: 'Настройки', + }, + status: { + nfcReady: 'NFC готов', + nfcOff: 'NFC выключен', + offline: 'Не в сети', + online: 'В сети', + noPrinters: 'Нет принтеров', + deviceOffline: 'Устройство не в сети', + waitingConnection: 'Ожидание подключения устройства...', + systemReady: 'Система готова', + status: 'Состояние', + }, + dashboard: { + readyToScan: 'Готово к сканированию', + idleMessage: 'Поставьте катушку на весы для идентификации', + nfcHint: 'Метка NFC будет считана автоматически', + device: 'Устройство', + syncWeight: 'Синхронизировать массу', + weightSynced: 'Синхронизировано!', + unknownTag: 'Неизвестная метка', + newTag: 'Обнаружена новая метка', + onScale: 'на весах', + linkSpool: 'Связать с катушкой', + linkTagTitle: 'Связать метку с катушкой', + linkTag: 'Связать метку', + selectSpool: 'Выберите катушку, с которой нужно связать эту метку:', + noUntagged: 'Катушки без меток не найдены', + tagDetected: 'Метка обнаружена', + noTag: 'Метка отсутствует', + tagId: 'Метка', + grossWeight: 'Масса брутто', + spoolSize: 'Размер катушки', + close: 'Закрыть', + currentSpool: 'Текущая катушка', + plateReady: 'Пластина готова: {{name}}', + plateReadyLabel: 'Пластины, готовые к очистке', + plateClearAction: 'Очищено', + plateClearedToast: 'Пластина отмечена как очищенная', + plateClearFailed: 'Не удалось отметить пластину как очищенную', + }, + modal: { + spoolDetected: 'Катушка обнаружена', + assignToAms: 'Назначить в AMS', + syncWeight: 'Синхронизировать массу', + weightSynced: 'Синхронизировано!', + syncing: 'Синхронизация...', + newTagDetected: 'Обнаружена новая метка', + addToInventory: 'Добавить в учёт', + assignToAmsTitle: 'Назначить в AMS', + selectSlot: 'Выберите слот', + assign: 'Назначить', + assigning: 'Назначение...', + assignSuccess: 'Назначено!', + assignPendingInsert: 'Назначено. Слот будет настроен после установки катушки.', + assignError: 'Не удалось назначить катушку. Повторите попытку.', + noPrinterSelected: 'Выберите принтер...', + noAmsDetected: 'На этом принтере AMS не обнаружена', + slot: 'Слот', + }, + weight: { + noReading: 'Нет показаний', + stable: 'Стабильно', + measuring: 'Измерение...', + tare: 'Тарировать', + calibrate: 'Калибровать', + }, + spool: { + remaining: 'Остаток', + material: 'Материал', + brand: 'Бренд', + color: 'Цвет', + coreWeight: 'Сердечник', + labelWeight: 'По этикетке', + scaleWeight: 'По весам', + netWeight: 'Нетто', + lastUsed: 'Последнее использование', + }, + ams: { + noData: 'AMS не обнаружена', + connectAms: 'Подключите AMS, чтобы увидеть слоты филамента', + noPrinter: 'Принтер не выбран', + selectPrinter: 'Выберите принтер на верхней панели', + printerDisconnected: 'Принтер отключён', + humidity: 'Влажность', + level: 'Уровень', + active: 'Активен', + slot: 'Слот', + empty: 'Пусто', + }, + inventory: { + search: 'Поиск катушек...', + empty: 'В учёте нет катушек', + noResults: 'Подходящие катушки не найдены', + spools: 'катушек', + addSpool: 'Добавить катушку', + }, + settings: { + tabDevice: 'Устройство', + tabDisplay: 'Экран', + tabScale: 'Весы', + tabUpdates: 'Обновления', + nfcReader: 'Считыватель NFC', + type: 'Тип', + connection: 'Подключение', + notConnected: 'Н/Д', + deviceInfo: 'Сведения об устройстве', + hostname: 'Хост', + uptime: 'Время работы', + systemConfig: 'Бэкенд и авторизация', + backendUrl: 'URL бэкенда Bambuddy', + apiToken: 'Токен API', + apiTokenPlaceholder: 'Введите токен API', + saveConfig: 'Сохранить конфигурацию', + systemQueued: 'Конфигурация поставлена в очередь.', + nfcDiagnostic: 'Диагностика NFC', + scaleDiagnostic: 'Диагностика весов', + readTagDiagnostic: 'Диагностика чтения метки', + testNfc: 'Проверить считыватель', + testScale: 'Проверить точность', + testReadTag: 'Считать метку', + systemFieldsRequired: 'Необходимо указать URL бэкенда.', + brightness: 'Яркость', + saved: 'Сохранено', + noBacklight: 'Подсветка DSI не обнаружена. Для управления яркостью требуется дисплей DSI.', + screenBlank: 'Тайм-аут отключения экрана', + screenBlankDesc: 'Экран выключается при бездействии. Коснитесь его для пробуждения.', + displayNote: 'Яркость регулируется программным фильтром.', + scaleCalibration: 'Калибровка весов', + currentWeight: 'Текущая масса', + tareOffset: 'Тара', + calFactor: 'Коэффициент', + knownWeight: 'Эталонная масса', + calStep1: 'Уберите всё с весов и нажмите «Установить ноль».', + calStep2: 'Положите на весы груз известной массы.', + setZero: 'Установить ноль', + calibrateNow: 'Калибровать', + calibrated: 'Откалибровано', + tareSet: 'Команда тарирования отправлена. Ожидание устройства...', + tareComplete: 'Тарирование завершено!', + tareTimedOut: 'Истекло время ожидания тарирования — демон SpoolBuddy запущен?', + tareFailed: 'Не удалось отправить команду тарирования', + zeroSet: 'Нулевая точка установлена. Положите на весы груз известной массы.', + calibrationDone: 'Калибровка завершена!', + calibrationFailed: 'Ошибка калибровки', + lastCalibrated: 'Последняя калибровка', + stable: 'Стабильно', + settling: 'Стабилизация...', + firmware: 'Прошивка', + scale: 'Весы', + noDevice: 'Устройство SpoolBuddy не найдено', + daemonVersion: 'Версия демона', + currentVersion: 'Текущая', + versionPending: 'Ожидание демона...', + checking: 'Проверка...', + checkUpdates: 'Проверить обновления', + updateAvailable: 'Доступно обновление', + updateInstructions: 'Обновление по SSH: запустите установочный скрипт SpoolBuddy.', + upToDate: 'Установлена актуальная версия', + includeBeta: 'Включать бета-версии', + }, + writeTag: { + tabExisting: 'Существующая катушка', + tabNew: 'Новая катушка', + tabReplace: 'Заменить метку', + searchPlaceholder: 'Поиск по материалу, цвету или бренду...', + noUntaggedSpools: 'Нет катушек без меток', + noTaggedSpools: 'Нет катушек с метками', + selectSpool: 'Выберите катушку, затем положите чистую метку NTAG на считыватель', + placeTag: 'Положите метку NTAG на считыватель', + tagReady: 'Метка обнаружена — можно записывать', + writeTag: 'Записать метку', + replaceTag: 'Заменить метку', + writing: 'Запись метки...', + waiting: 'Ожидание SpoolBuddy...', + writeSuccess: 'Метка успешно записана!', + writeFailed: 'Ошибка записи', + queueFailed: 'Не удалось поставить команду записи в очередь', + tryAgain: 'Повторить', + cancel: 'Отмена', + replaceWarning: 'Старая метка будет отвязана и заменена новой.', + deviceOffline: 'SpoolBuddy не в сети', + material: 'Материал', + colorName: 'Название цвета', + color: 'Цвет', + brand: 'Бренд', + weight: 'Масса (г)', + createSpool: 'Создать катушку', + creating: 'Создание...', + spoolCreated: 'Катушка создана! Можно записывать метку.', + createFailed: 'Не удалось создать катушку', + incompleteDataWarning: 'Метка записана с неполными данными Spoolman', + }, + quickMenu: { + printerPower: 'Питание принтера', + systemControls: 'Система', + restartDaemon: 'Перезапустить демон', + restartBrowser: 'Перезапустить браузер', + reboot: 'Перезагрузить', + shutdown: 'Выключить', + swipeToClose: 'Проведите вниз, чтобы закрыть', + confirmTitle: 'Подтверждение', + confirmShutdown: 'Выключить SpoolBuddy? Для повторного включения потребуется физический доступ.', + confirmReboot: 'Перезагрузить SpoolBuddy?', + confirmRestartDaemon: 'Перезапустить демон SpoolBuddy? NFC и весы временно будут недоступны.', + confirmRestartBrowser: 'Перезапустить браузер киоска? Экран ненадолго погаснет.', + confirm: 'Подтвердить', + confirmPlugOn: 'Включить {{name}}?', + confirmPlugOff: 'Выключить {{name}}?', + turnOn: 'Включить', + turnOff: 'Выключить', + }, + }, + systemHealth: { + sectionTitle: 'Состояние системы', + sectionDescription: 'Проверяет последние журналы на известные проблемы, которые обычно можно исправить самостоятельно до обращения в поддержку.', + rescan: 'Проверить снова', + clean: 'В последних {{times}} записях журнала известные проблемы не найдены.', + logUnavailable: 'Запись журналов в файл отключена, поэтому выполнить проверку невозможно. Включите файловое журналирование.', + learnMore: 'Как исправить', + fixLabel: 'Исправление:', + occurrences: 'Обнаружено {{times}} раз; последний раз — {{lastSeen}}', + category: { + layer8: 'Можно исправить самостоятельно', + environment: 'Окружение', + bug: 'Сообщите об ошибке', + }, + signature: { + 'ftp-auth-rejected': { + name: 'Принтер отклонил код доступа', + cause: 'Принтер отклонил вход в службу передачи файлов. Код доступа неверен либо изменился после переключения режима разработчика.', + fix: 'Снова скопируйте код доступа с экрана принтера в настройках LAN и обновите его в настройках принтера Bambuddy.', + }, + 'ftp-connection-timeout': { + name: 'Истекло время подключения к службе передачи файлов', + cause: 'Bambuddy не смог подключиться к порту передачи файлов принтера (FTPS 990). Порт заблокирован, принтер выключен либо находится в другой подсети.', + fix: 'Убедитесь, что порт 990 между Bambuddy и принтером не блокируется и оба устройства находятся в доступных друг другу сетях.', + }, + 'ftp-ssl-error': { + name: 'Ошибка защищённого соединения с файловой службой', + cause: 'Не удалось выполнить TLS-рукопожатие с сервером передачи файлов принтера. Частые причины — межсетевой экран или устаревшая прошивка принтера.', + fix: 'Обновите прошивку принтера и убедитесь, что межсетевой экран или прокси не перехватывает соединение на порту 990.', + }, + 'mqtt-connection-flapping': { + name: 'Подключение к принтеру постоянно обрывается', + cause: 'Управляющее соединение MQTT 8883 постоянно разрывается и восстанавливается. Обычно причина в нестабильной сети или частично заблокированном порте.', + fix: 'Проверьте уровень Wi‑Fi у принтера, по возможности используйте проводное подключение и убедитесь в стабильной доступности порта 8883.', + }, + 'camera-connection-refused': { + name: 'Видеопоток камеры недоступен', + cause: 'Камера недоступна по порту RTSPS 322. Порт заблокирован либо на принтере выключены камера или просмотр по LAN.', + fix: 'Включите камеру и просмотр по LAN на принтере и убедитесь, что порт 322 не заблокирован. На печать это не влияет.', + }, + 'database-locked': { + name: 'Конфликт записи в базу данных', + cause: 'Под нагрузкой SQLite выдаёт ошибки «database is locked». Это часто происходит при одновременной работе с несколькими принтерами.', + fix: 'Переведите Bambuddy на внешнюю базу PostgreSQL. См. руководство по PostgreSQL в документации.', + }, + }, + }, + vpDiagnostic: { + title: 'Проверка настройки — {{name}}', + runButton: 'Запустить проверку', + running: 'Выполняется проверка настройки...', + runFailed: 'Не удалось выполнить проверку: {{error}}', + retry: 'Запустить снова', + overall: { + ok: 'Все проверки пройдены — виртуальный принтер настроен правильно.', + warnings: 'Виртуальный принтер должен работать, но некоторые пункты требуют внимания.', + problems: 'Обнаружены проблемы, из-за которых слайсер не видит или не может использовать виртуальный принтер.', + }, + check: { + enabled: { + title: 'Виртуальный принтер включён', + fail: 'Виртуальный принтер выключен. Включите его, чтобы он обнаруживался в сети.', + }, + running: { + title: 'Службы запущены', + fail: 'Виртуальный принтер включён, но его службы не работают. Проверьте журнал Bambuddy: обычно запуску мешает конфликт IP-адреса привязки или ошибка прав доступа.', + }, + bind_interface: { + title: 'Сетевой интерфейс привязки', + fail: 'Интерфейс привязки не задан или больше не существует на этом хосте. Выберите актуальный интерфейс в списке «Интерфейс привязки».', + }, + access_code: { + title: 'Код доступа задан', + fail: 'Код доступа не задан. В слайсере необходимо указать тот же восьмизначный код, который задан здесь.', + }, + target_printer: { + title: 'Целевой принтер', + fail: 'Целевой принтер не выбран. Для режима прокси необходимо указать реальный принтер.', + warn: 'Целевой принтер сейчас не в сети. Перенаправление возобновится после его подключения.', + }, + port_ftps: { + title: 'Служба загрузки файлов (порт {{port}})', + fail: 'На порту {{port}} выбранного IP-адреса никто не слушает, поэтому слайсер не сможет загружать файлы. Обычно причина в конфликте порта на этом интерфейсе.', + }, + port_mqtt: { + title: 'Служба управления (порт {{port}})', + fail: 'На порту {{port}} выбранного IP-адреса никто не слушает, поэтому слайсер не сможет подключиться и отображать состояние.', + }, + port_bind: { + title: 'Служба обнаружения (порт {{port}})', + fail: 'На порту {{port}} выбранного IP-адреса никто не слушает, поэтому сетевое обнаружение слайсером не работает.', + }, + certificate: { + title: 'Сертификат TLS', + pass: 'Сертификат готов. Убедитесь, что сертификат центра сертификации Bambuddy, указанный выше, импортирован в доверенное хранилище слайсера.', + fail: 'Сертификат TLS для этого виртуального принтера отсутствует. Проверьте права записи в каталог данных Bambuddy.', + }, + }, + }, + gcodeViewer: { + back: 'Назад', + backToArchives: 'Вернуться в архив печати', + backToFiles: 'Вернуться в файловый менеджер', + }, + libraryPurge: { + title: 'Очистить старые файлы', + headerButton: 'Очистить старые', + headerTooltip: 'Массово переместить старые файлы в корзину', + description: 'За один проход убирает старые файлы из библиотеки. Для печатавшихся файлов возраст считается от даты последней печати, для ни разу не печатавшихся — от даты загрузки.', + ageLabel: 'Переместить файлы старше', + days: 'дней', + includeNeverPrinted: 'Включить файлы, которые ни разу не печатались', + effectsTitle: 'Что произойдёт после нажатия «Очистить»', + effect1: 'Подходящие файлы будут перемещены в корзину, но пока не удалены с диска.', + effect2: 'Их можно восстановить из корзины до окончания срока хранения.', + effect3: 'После окончания срока хранения очистка корзины окончательно удалит их с диска.', + effect4: 'Файлы во внешних подключённых папках пропускаются: Bambuddy не удаляет чужие данные.', + previewLoading: 'Подсчёт подходящих файлов…', + previewFailed: 'Не удалось выполнить предварительный расчёт.', + previewSummary: 'В корзину будет перемещено: {{count}} файлов · {{size}}', + andMore: '…и ещё {{count}}', + warning: 'Файлы в корзине продолжают занимать место до окончания срока хранения. Чтобы освободить диск сразу, после операции очистите корзину.', + confirmCta: 'Переместить в корзину: {{count}}', + purging: 'Перемещение в корзину…', + toast: { + success: 'Перемещено в корзину файлов: {{count}}.', + failed: 'Не удалось очистить файлы.', + }, + }, + libraryAutoPurge: { + enableLabel: 'Автоматически очищать старые файлы', + enableDescription: 'Раз в сутки запускает административную очистку. Сначала файлы попадают в корзину и не удаляются немедленно.', + ageLabel: 'Автоматически очищать файлы старше', + ageDescription: 'Минимум 7 дней, максимум 10 лет. Используется тот же способ расчёта возраста, что и при ручной очистке.', + days: 'дней', + includeNeverPrinted: 'Включить файлы, которые ни разу не печатались', + saveFailed: 'Не удалось сохранить настройки автоочистки.', + }, + archivePurge: { + headerButton: 'Очистить старые', + headerTooltip: 'Массово удалить старые записи архива', + title: 'Очистить старые записи архива', + description: 'Удаляет старую историю печати. Возраст записи считается от последнего завершения печати; повторная печать обновляет дату, поэтому используемые записи не удаляются.', + ageLabel: 'Удалить записи, которые не печатались последние', + days: 'дней', + effectsTitle: 'Что произойдёт после нажатия «Очистить»', + effect1: 'Каждая подходящая запись будет скрыта из списков, а связанные файлы удалены с диска: 3MF, миниатюра, таймлапс, исходный 3MF, проект F3D и фотографии.', + effect2: 'Строка архива останется в базе, поэтому быстрая статистика сохранит вклад по филаменту, времени, стоимости и энергии — как при обычном удалении отдельной записи.', + effect3: 'Установите флажок «Также удалить из статистики», чтобы исключить вклад из быстрой статистики. Это действие необратимо.', + effect4: 'Повторная печать обновляет дату записи, поэтому используемые архивы не удаляются.', + purgeStatsLabel: 'Также удалить из статистики', + purgeStatsHint: 'Исключает соответствующие записи из быстрой статистики по филаменту, времени, стоимости и энергии. Без этого удаляются только файлы, а статистика сохраняется.', + previewLoading: 'Подсчёт подходящих записей…', + previewFailed: 'Не удалось выполнить предварительный расчёт.', + previewSummary: 'Будет удалено: {{count}} записей · {{size}}', + andMore: '…и ещё {{count}}', + warning: 'Файлы будут удалены с диска без возможности восстановления. Перед продолжением скачайте или добавьте в избранное всё, что нужно сохранить.', + confirmCta: 'Удалить записей: {{count}}', + purging: 'Удаление…', + toast: { + success: 'Удалено записей архива: {{count}}.', + failed: 'Не удалось очистить архив.', + }, + }, + archiveAutoPurge: { + enableLabel: 'Автоматически очищать старые записи архива', + enableDescription: 'Раз в сутки скрывает записи из списков и удаляет их файлы с диска, если они не печатались в течение заданного срока. Повторная печать сбрасывает отсчёт.', + ageLabel: 'Автоматически удалять записи, которые не печатались последние', + ageDescription: 'Минимум 7 дней, максимум 10 лет. Срок считается от последнего завершения печати; повторная печать обновляет дату. Удаляются 3MF, миниатюра, таймлапс, исходный 3MF, F3D и фотографии.', + days: 'дней', + purgeStatsLabel: 'Также удалить из статистики', + purgeStatsDescription: 'Если включено, ежедневная очистка исключает удалённые записи из быстрой статистики по филаменту, времени, стоимости и энергии. По умолчанию выключено: статистика сохраняется, удаляются только файлы.', + runNow: 'Очистить архив сейчас', + saveFailed: 'Не удалось сохранить настройки автоочистки.', + }, +};