From b2ce82fe7ee72d736f0a457cc3dc79bf2a027fdb Mon Sep 17 00:00:00 2001 From: zjs81 Date: Sun, 11 Jan 2026 17:13:50 -0700 Subject: [PATCH] Add localization support and translation script - Introduced a new extension for localization in Flutter with `LocalizationExtension` in `l10n.dart`. - Added a Python script `translate.py` for translating ARB/JSON localization files using a local Ollama model, preserving keys and placeholders, and handling ICU format rules. --- l10n.yaml | 5 + lib/l10n/app_bg.arb | 1339 ++++++ lib/l10n/app_de.arb | 1339 ++++++ lib/l10n/app_en.arb | 1144 +++++ lib/l10n/app_es.arb | 1339 ++++++ lib/l10n/app_fr.arb | 1339 ++++++ lib/l10n/app_it.arb | 1339 ++++++ lib/l10n/app_localizations.dart | 4281 ++++++++++++++++++ lib/l10n/app_localizations_bg.dart | 2393 ++++++++++ lib/l10n/app_localizations_de.dart | 2395 ++++++++++ lib/l10n/app_localizations_en.dart | 2357 ++++++++++ lib/l10n/app_localizations_es.dart | 2389 ++++++++++ lib/l10n/app_localizations_fr.dart | 2402 ++++++++++ lib/l10n/app_localizations_it.dart | 2389 ++++++++++ lib/l10n/app_localizations_nl.dart | 2382 ++++++++++ lib/l10n/app_localizations_pl.dart | 2387 ++++++++++ lib/l10n/app_localizations_pt.dart | 2389 ++++++++++ lib/l10n/app_localizations_sk.dart | 2378 ++++++++++ lib/l10n/app_localizations_sl.dart | 2383 ++++++++++ lib/l10n/app_localizations_sv.dart | 2366 ++++++++++ lib/l10n/app_localizations_zh.dart | 2263 +++++++++ lib/l10n/app_nl.arb | 1339 ++++++ lib/l10n/app_pl.arb | 1339 ++++++ lib/l10n/app_pt.arb | 1339 ++++++ lib/l10n/app_sk.arb | 1339 ++++++ lib/l10n/app_sl.arb | 1339 ++++++ lib/l10n/app_sv.arb | 1339 ++++++ lib/l10n/app_zh.arb | 1339 ++++++ lib/l10n/l10n.dart | 6 + lib/main.dart | 15 + lib/models/app_settings.dart | 7 + lib/screens/app_debug_log_screen.dart | 13 +- lib/screens/app_settings_screen.dart | 307 +- lib/screens/ble_debug_log_screen.dart | 21 +- lib/screens/channel_chat_screen.dart | 45 +- lib/screens/channel_message_path_screen.dart | 143 +- lib/screens/channels_screen.dart | 136 +- lib/screens/chat_screen.dart | 169 +- lib/screens/contacts_screen.dart | 107 +- lib/screens/device_screen.dart | 11 +- lib/screens/map_cache_screen.dart | 79 +- lib/screens/map_screen.dart | 215 +- lib/screens/repeater_cli_screen.dart | 357 +- lib/screens/repeater_hub_screen.dart | 28 +- lib/screens/repeater_settings_screen.dart | 243 +- lib/screens/repeater_status_screen.dart | 81 +- lib/screens/scanner_screen.dart | 22 +- lib/screens/settings_screen.dart | 272 +- lib/screens/telemetry_screen.dart | 155 +- lib/services/app_settings_service.dart | 4 + lib/utils/dialog_utils.dart | 11 +- lib/widgets/debug_frame_viewer.dart | 34 +- lib/widgets/device_tile.dart | 5 +- lib/widgets/emoji_picker.dart | 37 +- lib/widgets/gif_picker.dart | 27 +- lib/widgets/list_filter_widget.dart | 29 +- lib/widgets/path_management_dialog.dart | 96 +- lib/widgets/path_selection_dialog.dart | 79 +- lib/widgets/quick_switch_bar.dart | 15 +- lib/widgets/repeater_login_dialog.dart | 48 +- lib/widgets/room_login_dialog.dart | 48 +- pubspec.lock | 7 +- pubspec.yaml | 4 + tools/translate.py | 723 +++ 64 files changed, 54716 insertions(+), 1254 deletions(-) create mode 100644 l10n.yaml create mode 100644 lib/l10n/app_bg.arb create mode 100644 lib/l10n/app_de.arb create mode 100644 lib/l10n/app_en.arb create mode 100644 lib/l10n/app_es.arb create mode 100644 lib/l10n/app_fr.arb create mode 100644 lib/l10n/app_it.arb create mode 100644 lib/l10n/app_localizations.dart create mode 100644 lib/l10n/app_localizations_bg.dart create mode 100644 lib/l10n/app_localizations_de.dart create mode 100644 lib/l10n/app_localizations_en.dart create mode 100644 lib/l10n/app_localizations_es.dart create mode 100644 lib/l10n/app_localizations_fr.dart create mode 100644 lib/l10n/app_localizations_it.dart create mode 100644 lib/l10n/app_localizations_nl.dart create mode 100644 lib/l10n/app_localizations_pl.dart create mode 100644 lib/l10n/app_localizations_pt.dart create mode 100644 lib/l10n/app_localizations_sk.dart create mode 100644 lib/l10n/app_localizations_sl.dart create mode 100644 lib/l10n/app_localizations_sv.dart create mode 100644 lib/l10n/app_localizations_zh.dart create mode 100644 lib/l10n/app_nl.arb create mode 100644 lib/l10n/app_pl.arb create mode 100644 lib/l10n/app_pt.arb create mode 100644 lib/l10n/app_sk.arb create mode 100644 lib/l10n/app_sl.arb create mode 100644 lib/l10n/app_sv.arb create mode 100644 lib/l10n/app_zh.arb create mode 100644 lib/l10n/l10n.dart create mode 100644 tools/translate.py diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 0000000..a4d323c --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,5 @@ +arb-dir: lib/l10n +template-arb-file: app_en.arb +output-localization-file: app_localizations.dart +output-class: AppLocalizations +nullable-getter: false diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb new file mode 100644 index 0000000..4c747da --- /dev/null +++ b/lib/l10n/app_bg.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "bg", + "appTitle": "MeshCore Open", + "nav_contacts": "Контакти", + "nav_channels": "Канали", + "nav_map": "Карта", + "common_cancel": "Отказ", + "common_connect": "Свържи се", + "common_unknownDevice": "Неизвестно устройство", + "common_save": "Запази", + "common_delete": "Изтрий", + "common_close": "Затвори", + "common_edit": "Редактирай", + "common_add": "Добави", + "common_settings": "Настройки", + "common_disconnect": "Прекъсни", + "common_connected": "Свързано", + "common_disconnected": "Откъснато", + "common_create": "Създай", + "common_continue": "Продължи", + "common_share": "Сподели", + "common_copy": "Копирай", + "common_retry": "Опитай отново", + "common_hide": "Скриване", + "common_remove": "Изтрий", + "common_enable": "Активирай", + "common_disable": "Деактивирай", + "common_reboot": "Рестартирай", + "common_loading": "Зареждане...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Сканиране за устройства...", + "scanner_connecting": "Свързвам се...", + "scanner_disconnecting": "Изключване...", + "scanner_notConnected": "Не е свързан", + "scanner_connectedTo": "Свързано с {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Търсене на устройства MeshCore...", + "scanner_tapToScan": "Натиснете Сканиране, за да намерите устройства MeshCore.", + "scanner_connectionFailed": "Връзката не успя: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Спрете", + "scanner_scan": "Сканирай", + "device_quickSwitch": "Бързо превключване", + "device_meshcore": "MeshCore", + "settings_title": "Настройки", + "settings_deviceInfo": "Информация за устройството", + "settings_appSettings": "Настройки на приложението", + "settings_appSettingsSubtitle": "Уведомления, съобщения и предпочитания за карта", + "settings_nodeSettings": "Настройки на възела", + "settings_nodeName": "Име на възела", + "settings_nodeNameNotSet": "Не е зададено", + "settings_nodeNameHint": "Въведете име на възел", + "settings_nodeNameUpdated": "Името е актуализирано", + "settings_radioSettings": "Настройки на радиопредавателя", + "settings_radioSettingsSubtitle": "Честота, мощност, разпространяващ фактор", + "settings_radioSettingsUpdated": "Радио настройките са актуализирани", + "settings_location": "Местоположение", + "settings_locationSubtitle": "Координати на GPS", + "settings_locationUpdated": "Местоположението е актуализирано", + "settings_locationBothRequired": "Въведете както географска ширина, така и географска дължина.", + "settings_locationInvalid": "Невалидна ширина или дължина.", + "settings_latitude": "Широчина", + "settings_longitude": "Дължина", + "settings_privacyMode": "Режим на поверителност", + "settings_privacyModeSubtitle": "Скриване на име/местоположение в рекламите", + "settings_privacyModeToggle": "Активирайте режим на поверителност, за да скриете името и местоположението си в рекламите.", + "settings_privacyModeEnabled": "Режим на поверителност е активиран", + "settings_privacyModeDisabled": "Режим на поверителност е деактивиран", + "settings_actions": "Действия", + "settings_sendAdvertisement": "Изпрати Реклама", + "settings_sendAdvertisementSubtitle": "Сега присъствие в ефир", + "settings_advertisementSent": "Реклама изпратена", + "settings_syncTime": "Време за синхронизация", + "settings_syncTimeSubtitle": "Задайте часовника на устройството да отговаря на времето на телефона.", + "settings_timeSynchronized": "Синхронизирано във времето", + "settings_refreshContacts": "Презареди контакти", + "settings_refreshContactsSubtitle": "Презареди списъка с контакти от устройството", + "settings_rebootDevice": "Рестартирайте устройството", + "settings_rebootDeviceSubtitle": "Рестартирайте устройството MeshCore", + "settings_rebootDeviceConfirm": "Сигурни ли сте, че искате да рестартирате устройството? Ще бъдете откъснати.", + "settings_debug": "Отстрани", + "settings_bleDebugLog": "Лог за отстраняване на грешки на BLE", + "settings_bleDebugLogSubtitle": "Команди, отговори и сурови данни BLE", + "settings_appDebugLog": "Лог на отстраняване на грешки на приложението", + "settings_appDebugLogSubtitle": "Съобщения за отстраняване на грешки на приложението", + "settings_about": "За нас", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "Проект MeshCore с отворен код 2024 г.", + "settings_aboutDescription": "Отворен софтуер за Flutter клиент за MeshCore LoRa мрежови устройства.", + "settings_infoName": "Име", + "settings_infoId": "ИД", + "settings_infoStatus": "Статус", + "settings_infoBattery": "Батерия", + "settings_infoPublicKey": "Общ публичен ключ", + "settings_infoContactsCount": "Брой контакти", + "settings_infoChannelCount": "Брой канали", + "settings_presets": "Предварителни настройки", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Честота (MHz)", + "settings_frequencyHelper": "300.0 - 2500.0", + "settings_frequencyInvalid": "Невалидна честота (300-2500 MHz)", + "settings_bandwidth": "Ширина на честотния спектър", + "settings_spreadingFactor": "Фактор на разпространение", + "settings_codingRate": "Такса за кодиране", + "settings_txPower": "TX Мощност (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Невалидна мощност на TX (0-22 dBm)", + "settings_longRange": "Дълъг обхват", + "settings_fastSpeed": "Бърза скорост", + "settings_error": "Грешка: {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "Настройки на приложението", + "appSettings_appearance": "Външен вид", + "appSettings_theme": "Тема", + "appSettings_themeSystem": "Система по подразбиране", + "appSettings_themeLight": "Ярка", + "appSettings_themeDark": "Тъмно", + "appSettings_language": "Език", + "appSettings_languageSystem": "Система по подразбиране", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Уведомления", + "appSettings_enableNotifications": "Активирай Известия", + "appSettings_enableNotificationsSubtitle": "Получете известия за съобщения и реклами", + "appSettings_notificationPermissionDenied": "Отказвано е разрешение за известия", + "appSettings_notificationsEnabled": "Уведомителни са активирани", + "appSettings_notificationsDisabled": "Известия са изключени", + "appSettings_messageNotifications": "Уведомления", + "appSettings_messageNotificationsSubtitle": "Покажи известие при получаване на нови съобщения", + "appSettings_channelMessageNotifications": "Уведомления за съобщения от канал", + "appSettings_channelMessageNotificationsSubtitle": "Покажи известие при получаване на съобщения от канали", + "appSettings_advertisementNotifications": "Уведомления за реклами", + "appSettings_advertisementNotificationsSubtitle": "Покажи известие, когато бъдат открити нови възли.", + "appSettings_messaging": "Съобщения", + "appSettings_clearPathOnMaxRetry": "Изчисти Път на Макс Опит", + "appSettings_clearPathOnMaxRetrySubtitle": "Възстанови контактния път след 5 неуспешни опита за изпращане", + "appSettings_pathsWillBeCleared": "Пътищата ще бъдат почистени след 5 неуспешни опита.", + "appSettings_pathsWillNotBeCleared": "Пътищата няма да бъдат автоматично изчистени.", + "appSettings_autoRouteRotation": "Автоматично маршрутизиране на завъртания", + "appSettings_autoRouteRotationSubtitle": "Превключете между най-добрите пътища и режим на наводняване", + "appSettings_autoRouteRotationEnabled": "Автоматично маршрутизиране вкл.", + "appSettings_autoRouteRotationDisabled": "Автоматично маршрутизирането е деактивирано", + "appSettings_battery": "Батерия", + "appSettings_batteryChemistry": "Химия на батерията", + "appSettings_batteryChemistryPerDevice": "Зададено за устройство ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Свържете се с устройство, за да изберете.", + "appSettings_batteryNmc": "18650 NMC (3.0-4.2V)", + "appSettings_batteryLifepo4": "Литиево желязо фосфат (2.6-3.65V)", + "appSettings_batteryLipo": "Литиев полимер (3.0-4.2V)", + "appSettings_mapDisplay": "Карта за показване", + "appSettings_showRepeaters": "Показване на повторители", + "appSettings_showRepeatersSubtitle": "Показване на възпроизвеждащи се възли на картата", + "appSettings_showChatNodes": "Покажи Възли на Чат", + "appSettings_showChatNodesSubtitle": "Показване на чат възли на картата", + "appSettings_showOtherNodes": "Покажи други възли", + "appSettings_showOtherNodesSubtitle": "Покажи други типове възли на картата", + "appSettings_timeFilter": "Филтриране по време", + "appSettings_timeFilterShowAll": "Покажи всички възли", + "appSettings_timeFilterShowLast": "Покажи възли от последните {hours} часа", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Филтри за време на картата", + "appSettings_showNodesDiscoveredWithin": "Покажи възлите, открити в:", + "appSettings_allTime": "Всичко време", + "appSettings_lastHour": "Последната минута", + "appSettings_last6Hours": "Последни 6 часа", + "appSettings_last24Hours": "Последно 24 часа", + "appSettings_lastWeek": "Миналата седмица", + "appSettings_offlineMapCache": "Кеш на офлайн карти", + "appSettings_noAreaSelected": "Няма избрана област", + "appSettings_areaSelectedZoom": "Избрана е област (мащаб {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Отстрани", + "appSettings_appDebugLogging": "Логване за отстраняване на грешки на приложението", + "appSettings_appDebugLoggingSubtitle": "Записване на съобщения за отстраняване на грешки от приложението за отстраняване на грешки.", + "appSettings_appDebugLoggingEnabled": "Режимът за отстраняване на грешки в приложението е активиран.", + "appSettings_appDebugLoggingDisabled": "Логването за отстраняване на грешки в приложението е изключено.", + "contacts_title": "Контакти", + "contacts_noContacts": "Няма контакти към момента.", + "contacts_contactsWillAppear": "Контактите ще се появят, когато устройствата рекламират.", + "contacts_searchContacts": "Търсене на контакти...", + "contacts_noUnreadContacts": "Няма непрочетени контакти", + "contacts_noContactsFound": "Няма намерени контакти или групи.", + "contacts_deleteContact": "Изтрий Контакт", + "contacts_removeConfirm": "Изтрий {contactName} от контактите?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Управление на Повтарящ се Елемент", + "contacts_roomLogin": "Вход в стаята", + "contacts_openChat": "Отвори чат", + "contacts_editGroup": "Редактирай Група", + "contacts_deleteGroup": "Изтрий група", + "contacts_deleteGroupConfirm": "Премахнете \"{groupName}\"?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Нова група", + "contacts_groupName": "Група", + "contacts_groupNameRequired": "Името на групата е задължително.", + "contacts_groupAlreadyExists": "Групата \"{name}\" вече съществува.", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Филтрирайте контактите...", + "contacts_noContactsMatchFilter": "Няма съвпадения с вашия филтър.", + "contacts_noMembers": "Няма членове", + "contacts_lastSeenNow": "Последно видяно сега", + "contacts_lastSeenMinsAgo": "Последна активност {minutes} минути преди", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Последно видяно преди час", + "contacts_lastSeenHoursAgo": "Последно видян {hours} часа преди.", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Последно видяно преди 1 ден", + "contacts_lastSeenDaysAgo": "Последно видян {days} дни преди.", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Канали", + "channels_noChannelsConfigured": "Няма конфигурирани канали", + "channels_addPublicChannel": "Добави публичен канал", + "channels_searchChannels": "Търсене на канали...", + "channels_noChannelsFound": "Няма намерени канали", + "channels_channelIndex": "Канал {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Канал с хаштаг", + "channels_public": "Публично", + "channels_private": "Личен", + "channels_publicChannel": "Публичен канал", + "channels_privateChannel": "Частен канал", + "channels_editChannel": "Редактирай канал", + "channels_deleteChannel": "Изтрий канала", + "channels_deleteChannelConfirm": "Изтрий \"{name}\"? Това не може да бъде отменено.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Каналът \"{name}\" е изтрит", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Добави Канал", + "channels_channelIndexLabel": "Индекс на канал", + "channels_channelName": "Име на канала", + "channels_usePublicChannel": "Използвайте публичен канал", + "channels_standardPublicPsk": "Стандартен публичен PSK", + "channels_pskHex": "PSK (Hex)", + "channels_generateRandomPsk": "Генерирай случайна PSK", + "channels_enterChannelName": "Моля, въведете име на канал.", + "channels_pskMustBe32Hex": "PSK трябва да бъде 32 шестнаредни знака.", + "channels_channelAdded": "Каналът \"{name}\" е добавен", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Редактирай Канал {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "Компресия SMAZ", + "channels_channelUpdated": "Каналът \"{name}\" е актуализиран", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "Публичен канал добавен", + "channels_sortBy": "Сортирай по", + "channels_sortManual": "Ръчно", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "Последни съобщения", + "channels_sortUnread": "Непрочетено", + "chat_noMessages": "Няма съобщения.", + "chat_sendMessageToStart": "Изпрати съобщение, за да започнеш.", + "chat_originalMessageNotFound": "Съобщението не е намерено", + "chat_replyingTo": "Отговарям на {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Отговори на {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Местоположение", + "chat_sendMessageTo": "Изпрати съобщение на {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Въведете съобщение...", + "chat_messageTooLong": "Съобщението е твърде дълго (макс {maxBytes} байта).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Съобщението е копирано", + "chat_messageDeleted": "Съобщението е изтрито", + "chat_retryingMessage": "Опитваме се отново.", + "chat_retryCount": "Опитай отново {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "Изпрати GIF", + "chat_reply": "Отговори", + "chat_addReaction": "Добави Реакция", + "chat_me": "Аз", + "emojiCategorySmileys": "Емотикони", + "emojiCategoryGestures": "Жестове", + "emojiCategoryHearts": "Сърца", + "emojiCategoryObjects": "Обекти", + "gifPicker_title": "Изберете GIF", + "gifPicker_searchHint": "Търсене на GIF-ове...", + "gifPicker_poweredBy": "Задвижвано от GIPHY", + "gifPicker_noGifsFound": "Няма намерени GIF файлове.", + "gifPicker_failedLoad": "Не можа да се заредят GIF файловете", + "gifPicker_failedSearch": "Неуспешно търсене на GIF-ове", + "gifPicker_noInternet": "Няма интернет връзка", + "debugLog_appTitle": "Лог на отстраняване на грешки на приложението", + "debugLog_bleTitle": "Лог за отстраняване на грешки на BLE", + "debugLog_copyLog": "Копирай лог", + "debugLog_clearLog": "Изчисти логовете", + "debugLog_copied": "Копирано лого за отстраняване на грешки", + "debugLog_bleCopied": "Копиран лог от BLE", + "debugLog_noEntries": "Все още няма дебъг логове.", + "debugLog_enableInSettings": "Активирайте отстраняване на грешки в настройките на приложението", + "debugLog_frames": "Рамки", + "debugLog_rawLogRx": "Raw Log-RX", + "debugLog_noBleActivity": "Няма BLE активност към момента.", + "debugFrame_length": "Дължина на кадъра: {count} байта", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Команда: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Съобщение:", + "debugFrame_destinationPubKey": "- Дестинация Публичен Ключ: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Време: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Флагове: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- Тип текст: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Просто", + "debugFrame_text": "- Текст: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Хексадесетичен Dump:", + "chat_pathManagement": "Управление на пътища", + "chat_routingMode": "Режим на маршрутизиране", + "chat_autoUseSavedPath": "Автоматично (използвай запазения път)", + "chat_forceFloodMode": "Принуди режим на наводняване", + "chat_recentAckPaths": "Неотдавни ACK пътища (докоснете, за да използвате):", + "chat_pathHistoryFull": "Историята на пътя е пълна. Премахнете записи, за да добавите нови.", + "chat_hopSingular": "скочи", + "chat_hopPlural": "скоци", + "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "Успехи", + "chat_removePath": "Премахни пътя", + "chat_noPathHistoryYet": "Няма история на пътищата още.\nИзпратете съобщение, за да откриете пътища.", + "chat_pathActions": "Действия по пътя:", + "chat_setCustomPath": "Задайте персонализиран път", + "chat_setCustomPathSubtitle": "Ръчно укажете маршрутен път", + "chat_clearPath": "Почисти Път", + "chat_clearPathSubtitle": "Принуди преоткриване при следващо изпращане", + "chat_pathCleared": "Пътят е почистен. Следващото съобщение ще открие маршрута отново.", + "chat_floodModeSubtitle": "Използвайте превключвателя за маршрутизиране в лентата на приложението.", + "chat_floodModeEnabled": "Режим на наводнение е активиран. Включете го отново чрез иконката за маршрутизиране в лентата на приложението.", + "chat_fullPath": "Пълен път", + "chat_pathDetailsNotAvailable": "Детайлите за пътя все още не са налични. Опитайте да изпратите съобщение, за да освежите.", + "chat_pathSetHops": "Пътят е зададен: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Запазено локално. Свържете се за синхронизиране.", + "chat_pathDeviceConfirmed": "Устройство потвърдено.", + "chat_pathDeviceNotConfirmed": "Устройството все още не е потвърдено.", + "chat_type": "Въведете", + "chat_path": "Пътекино", + "chat_publicKey": "Публичен ключ", + "chat_compressOutgoingMessages": "Компресиране на изходящи съобщения", + "chat_floodForced": "Потоп (принуден)", + "chat_directForced": "Директно (принудително)", + "chat_hopsForced": "{count} скока (принудително)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Потоп (автоматично)", + "chat_direct": "Директно", + "chat_poiShared": "Споделено място от интерес", + "chat_unread": "Непрочетени: {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Карта на възлите", + "map_noNodesWithLocation": "Няма възли с данни за местоположение.", + "map_nodesNeedGps": "Възлагат се възлозите да споделят техните GPS координати,\nза да се появят на картата.", + "map_nodesCount": "Нодове: {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Ключове: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Чат", + "map_repeater": "Повтарящ се", + "map_room": "Стая", + "map_sensor": "Датчик", + "map_pinDm": "Задържане (DM)", + "map_pinPrivate": "Задържане (Приватно)", + "map_pinPublic": "Публичен ключ", + "map_lastSeen": "Последна видяна", + "map_disconnectConfirm": "Сигурни ли сте, че искате да се откъснете от това устройство?", + "map_from": "От", + "map_source": "Източник", + "map_flags": "Флаг", + "map_shareMarkerHere": "Споделете маркер тук", + "map_pinLabel": "Етикетиране на пин", + "map_label": "Етикет", + "map_pointOfInterest": "Точка на интерес", + "map_sendToContact": "Изпрати на контакт", + "map_sendToChannel": "Изпрати в канала", + "map_noChannelsAvailable": "Няма налични канали", + "map_publicLocationShare": "Споделяне на публично място", + "map_publicLocationShareConfirm": "Ще споделите местоположение в {channelLabel}. Този канал е публичен и всеки с PSK може да го види.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Свържете се с устройство, за да споделите маркери.", + "map_filterNodes": "Филтрирайте възли", + "map_nodeTypes": "Типове възли", + "map_chatNodes": "Възли на чата", + "map_repeaters": "Повторители", + "map_otherNodes": "Други възли", + "map_keyPrefix": "Префикс на ключа", + "map_filterByKeyPrefix": "Филтрирайте по префикс на ключ", + "map_publicKeyPrefix": "Префикс на публичен ключ", + "map_markers": "Маркери", + "map_showSharedMarkers": "Покажи споделени маркери", + "map_lastSeenTime": "Последна видяна дата", + "map_sharedPin": "Споделено копие", + "map_joinRoom": "Присъедини се към стаята", + "map_manageRepeater": "Управление на Повтарящ се Елемент", + "mapCache_title": "Кеш на офлайн карти", + "mapCache_selectAreaFirst": "Изберете област за кеширане първа", + "mapCache_noTilesToDownload": "Няма плочки за изтегляне за тази област.", + "mapCache_downloadTilesTitle": "Изтегли плочки", + "mapCache_downloadTilesPrompt": "Изтегли {count} плочки за офлайн употреба?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Изтегли", + "mapCache_cachedTiles": "Кеширани {count} плочки", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Запазени {downloaded} плочки ({failed} неуспешни)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Изчисти офлайн кеша", + "mapCache_clearOfflineCachePrompt": "Премахнете всички кеширани плочки на картата?", + "mapCache_offlineCacheCleared": "Кешът на устройството е изчистен.", + "mapCache_noAreaSelected": "Няма избрана област", + "mapCache_cacheArea": "Област с кеш", + "mapCache_useCurrentView": "Използвайте текущия изглед", + "mapCache_zoomRange": "Обхват на увеличението", + "mapCache_estimatedTiles": "Очаквани плочки: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Изтеглено {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Изтегли Плочки", + "mapCache_clearCacheButton": "Изчисти кеша", + "mapCache_failedDownloads": "Неуспешни изтегляния: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "Север {north}, Юг {south}, Изток {east}, Запад {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Сега", + "time_minutesAgo": "{minutes} минути преди", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours} часа преди", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} дни преди", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "час", + "time_hours": "часове", + "time_day": "ден", + "time_days": "дни", + "time_week": "седмица", + "time_weeks": "секти", + "time_month": "месец", + "time_months": "месеци", + "time_minutes": "минути", + "time_allTime": "Всичко време", + "dialog_disconnect": "Прекъсни", + "dialog_disconnectConfirm": "Сигурни ли сте, че искате да се откъснете от това устройство?", + "login_repeaterLogin": "Повторител Вход", + "login_roomLogin": "Вход в стаята", + "login_password": "Парола", + "login_enterPassword": "Въведете парола", + "login_savePassword": "Запази парола", + "login_savePasswordSubtitle": "Паролата ще бъде съхранена сигурно на това устройство.", + "login_repeaterDescription": "Въведете паролата на репитера, за да получите достъп до настройките и статуса.", + "login_roomDescription": "Въведете паролата на стаята, за да получите достъп до настройките и статуса.", + "login_routing": "Маршрутизиране", + "login_routingMode": "Режим на маршрутизиране", + "login_autoUseSavedPath": "Автоматично (използвай запазения път)", + "login_forceFloodMode": "Принуди режим на наводняване", + "login_managePaths": "Управление на пътища", + "login_login": "Вход", + "login_attempt": "Опитвате {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Входът не беше успешен: {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Презареди", + "common_clear": "Изчисти", + "path_currentPath": "Текущ път: {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Използване на {count} {count, plural, =1{hop} other{hops}} път", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Въведете персонализиран път", + "path_currentPathLabel": "Текущ път", + "path_hexPrefixInstructions": "Въведете 2-символни шестнадесетични префикси за всеки хоп, разделени с кама.", + "path_hexPrefixExample": "A1,F2,3C (всяка нода използва първия байт от публичния си ключ)", + "path_labelHexPrefixes": "Пътеки (шестнадесетични префикси)", + "path_helperMaxHops": "Максимум 64 скока. Всеки префикс е 2 шестнадесетични знака (1 байт).", + "path_selectFromContacts": "Изберете от контакти:", + "path_noRepeatersFound": "Няма намерени репетитори или сървъри на стаи.", + "path_customPathsRequire": "Персонализираните пътища изискват междинни скокове, които могат да препращат съобщения.", + "path_invalidHexPrefixes": "Невалидни шестнадесетични префикси: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "Пътят е твърде дълъг. Максимум 64 скока са разрешени.", + "path_setPath": "Задайте път", + "repeater_management": "Управление на повторители", + "repeater_managementTools": "Инструменти за управление", + "repeater_status": "Статус", + "repeater_statusSubtitle": "Прегледайте статуса, статистиката и съседните устройства.", + "repeater_telemetry": "Телеметрия", + "repeater_telemetrySubtitle": "Прегледайте телеметрията на сензорите и системните статистики", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Изпрати команди към ретранслатора", + "repeater_settings": "Настройки", + "repeater_settingsSubtitle": "Конфигурирайте параметрите на репитера", + "repeater_statusTitle": "Статус на повтарянето", + "repeater_routingMode": "Режим на маршрутизиране", + "repeater_autoUseSavedPath": "Автоматично (използвай запазения път)", + "repeater_forceFloodMode": "Принуди режим на наводняване", + "repeater_pathManagement": "Управление на пътища", + "repeater_refresh": "Презареди", + "repeater_statusRequestTimeout": "Заявката за статус премина прекалено дълго.", + "repeater_errorLoadingStatus": "Грешка при зареждане на статуса: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Информация за системата", + "repeater_battery": "Батерия", + "repeater_clockAtLogin": "Часовник (при влизане)", + "repeater_uptime": "Наличност", + "repeater_queueLength": "Дължина на опашката", + "repeater_debugFlags": "Контролни точки за отстраняване на грешки", + "repeater_radioStatistics": "Статистика на радиостанциите", + "repeater_lastRssi": "Последна RSSI", + "repeater_lastSnr": "Последна SNR", + "repeater_noiseFloor": "Ниво на шум", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Статистика на пакетите", + "repeater_sent": "Изпратено", + "repeater_received": "Получено", + "repeater_duplicates": "Дубликати", + "repeater_daysHoursMinsSecs": "{days} дни {hours}ч {minutes}м {seconds}с", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Общо: {total}, Наводнение: {flood}, Директно: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Общо: {total}, Наводнение: {flood}, Директно: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Поливане: {flood}, Директен: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Общо: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Настройки на повтарящия се елемент", + "repeater_basicSettings": "Основни настройки", + "repeater_repeaterName": "Име на повтарящ се елемент", + "repeater_repeaterNameHelper": "Показване на името на този репитер", + "repeater_adminPassword": "Парола на администратора", + "repeater_adminPasswordHelper": "Пълен достъпен парола", + "repeater_guestPassword": "Парола на гост", + "repeater_guestPasswordHelper": "Достъп с ограничен достъп", + "repeater_radioSettings": "Настройки на радиостанцията", + "repeater_frequencyMhz": "Честота (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Power", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Ширина на честотния спектър", + "repeater_spreadingFactor": "Фактор на разпространение", + "repeater_codingRate": "Такса за кодиране", + "repeater_locationSettings": "Настройки на местоположението", + "repeater_latitude": "Широчина", + "repeater_latitudeHelper": "Десетични градуси (напр. 37.7749)", + "repeater_longitude": "Дължина", + "repeater_longitudeHelper": "Градуси с десетични знаци (напр. -122.4194)", + "repeater_features": "Характеристики", + "repeater_packetForwarding": "Пренасочване на пакети", + "repeater_packetForwardingSubtitle": "Активирайте репитера, за да препращате пакети.", + "repeater_guestAccess": "Достъп за Гост", + "repeater_guestAccessSubtitle": "Разрешете самочетене за гости", + "repeater_privacyMode": "Режим на поверителност", + "repeater_privacyModeSubtitle": "Скриване на име/местоположение в рекламите", + "repeater_advertisementSettings": "Настройки на рекламите", + "repeater_localAdvertInterval": "Местен Рекламен Интервал", + "repeater_localAdvertIntervalMinutes": "{minutes} минути", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Интервал на рекламата за наводнения", + "repeater_floodAdvertIntervalHours": "{hours} часа", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Криптиран Рекламен Интервал", + "repeater_dangerZone": "Опасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно", + "repeater_rebootRepeater": "БеРестартирай Репитер", + "repeater_rebootRepeaterSubtitle": "Рестартирайте ретранслатора.", + "repeater_rebootRepeaterConfirm": "Сигурни ли сте, че искате да рестартирате този репитер?", + "repeater_regenerateIdentityKey": "Генериране на Ключ за Идентичност", + "repeater_regenerateIdentityKeySubtitle": "Генериране на нова двойка публичен/частен ключ", + "repeater_regenerateIdentityKeyConfirm": "БеТова ще генерира нова идентичност за репитера. Продължете?", + "repeater_eraseFileSystem": "Изтрий Файлова Система", + "repeater_eraseFileSystemSubtitle": "Форматирайте файла на репитера", + "repeater_eraseFileSystemConfirm": "ВНИМАНИЕ: Това ще изтрие всички данни от репетитора. Това не може да бъде отменено!", + "repeater_eraseSerialOnly": "Изтриването е достъпно само през серийния терминал.", + "repeater_commandSent": "Командата е изпратена: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Грешка при изпращане на командата: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "БеПотвърди", + "repeater_settingsSaved": "Настройките са запазени успешно.", + "repeater_errorSavingSettings": "Грешка при запазване на настройките: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Обнови Основни Настройки", + "repeater_refreshRadioSettings": "Обнови настройките на радиопредавателите", + "repeater_refreshTxPower": "Обнови TX захранване", + "repeater_refreshLocationSettings": "Обнови настройките на местоположението", + "repeater_refreshPacketForwarding": "Обнови пакетно пренасочване", + "repeater_refreshGuestAccess": "Обнови достъп за гости", + "repeater_refreshPrivacyMode": "Обнови Режим на поверителност", + "repeater_refreshAdvertisementSettings": "Обнови Настройки на Рекламата", + "repeater_refreshed": "{label} е обновено", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Грешка при обновяване на {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Повторител CLI", + "repeater_debugNextCommand": "Поправи Следваща Команда", + "repeater_commandHelp": "Помощ", + "repeater_clearHistory": "Изчисти История", + "repeater_noCommandsSent": "Няма изпратени команди засега.", + "repeater_typeCommandOrUseQuick": "Въведете команда по-долу или използвайте бързи команди", + "repeater_enterCommandHint": "Въведете команда...", + "repeater_previousCommand": "Предходна команда", + "repeater_nextCommand": "Следваща команда", + "repeater_enterCommandFirst": "Въведете първо команда.", + "repeater_cliCommandFrameTitle": "Рамка за команда CLI", + "repeater_cliCommandError": "Грешка: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Получи име", + "repeater_cliQuickGetRadio": "Получи радио", + "repeater_cliQuickGetTx": "Получи TX", + "repeater_cliQuickNeighbors": "Съседи", + "repeater_cliQuickVersion": "Версия", + "repeater_cliQuickAdvertise": "Рекламирай", + "repeater_cliQuickClock": "Часовник", + "repeater_cliHelpAdvert": "Изпраща рекламен пакет", + "repeater_cliHelpReboot": "Рестартира устройството. (Забележка, може да получите 'Timeout', което е нормално)", + "repeater_cliHelpClock": "Показва текущото време според часовника на всяко устройство.", + "repeater_cliHelpPassword": "Задава се нова администраторска парола за устройството.", + "repeater_cliHelpVersion": "Показва версията на устройството и датата на компилация на фърмуера.", + "repeater_cliHelpClearStats": "Рестартира различни статистики броячи до нула.", + "repeater_cliHelpSetAf": "Задава времето на фактора.", + "repeater_cliHelpSetTx": "Задава се мощността на предаване на LoRa в dBm (отчитане спрямо референтно ниво).", + "repeater_cliHelpSetRepeat": "Активира или деактивира ролята на репитера за този възел.", + "repeater_cliHelpSetAllowReadOnly": "(Сървър на стаята) Ако е \"включено\", тогава влизането с празен парола ще бъде разрешено, но не може да публикува в стаята (само четене).", + "repeater_cliHelpSetFloodMax": "Задава максималния брой хопове на входящ пакет за заливване (ако >= max, пакетът не се предава).", + "repeater_cliHelpSetIntThresh": "Задава праг на интерференцията (в dB). По подразбиране е 14. Задайте на 0, за да деактивирате откриването на интерференция на каналите.", + "repeater_cliHelpSetAgcResetInterval": "Задава интервала за рестартиране на Автоматичния контролер за усилване. Задайте на 0, за да го деактивирате.", + "repeater_cliHelpSetMultiAcks": "Активира или деактивира функцията 'двойни ACKs'.", + "repeater_cliHelpSetAdvertInterval": "Задава интервала на таймера в минути за изпращане на локален (безпроблемен) рекламен пакет. Задайте на 0, за да го деактивирате.", + "repeater_cliHelpSetFloodAdvertInterval": "Задава интервала на таймера в часове за изпращане на пакет с реклама за наводнение. Задайте на 0, за да го деактивирате.", + "repeater_cliHelpSetGuestPassword": "Задава/обновява паролата на гост. (за повторители, гостите могат да изпращат заявката \"Get Stats\")", + "repeater_cliHelpSetName": "Задава име на обявата.", + "repeater_cliHelpSetLat": "Задава географска ширина на картата с реклами (в десетими градуси).", + "repeater_cliHelpSetLon": "Задава обхвата на дължина на картата на рекламата. (десетими градуса)", + "repeater_cliHelpSetRadio": "Задава напълно нови радио параметри и ги запазва в предпочитанията. Изисква команда \"рестарт\", за да бъдат приложени.", + "repeater_cliHelpSetRxDelay": "Зададени (експериментални) основи (трябва да е > 1 за ефект) за прилагане на леко забавяне на получените пакети, базирано на силата на сигнала/резултата. Задайте на 0, за да го деактивирате.", + "repeater_cliHelpSetTxDelay": "Задава фактор, умножен по времето на въздух за пакет в режим на наводнение и с рандомизирана система за слотове, за да забави предаването му (за да намали вероятността от сблъсъци).", + "repeater_cliHelpSetDirectTxDelay": "Същото като txdelay, но за прилагане на случайна забавяне при препращането на пакети в директен режим.", + "repeater_cliHelpSetBridgeEnabled": "Активиране/Деактивиране на мост.", + "repeater_cliHelpSetBridgeDelay": "Задайте забавяне преди преизпращане на пакети.", + "repeater_cliHelpSetBridgeSource": "Изберете дали мостът ще предава препратени пакети или получени пакети.", + "repeater_cliHelpSetBridgeBaud": "Задайте скоростта на предаване за RS232 мостовете.", + "repeater_cliHelpSetBridgeSecret": "Задайте тайна за мостовете на EspNow.", + "repeater_cliHelpSetAdcMultiplier": "Задава персонализиран коефициент за коригиране на отчетеното напрежение на батерията (поддържа се само на избрани дъски).", + "repeater_cliHelpTempRadio": "Задава временни радио параметри за посочения брой минути, връщайки се към оригиналните радио параметри след това. (не се запазва в предпочитанията).", + "repeater_cliHelpSetPerm": "Променя ACL. Премахва съответстващия запис (по префикс на pubkey), ако \"permissions\" е нула. Добавя нов запис, ако pubkey-hex е с пълна дължина и не е в ACL. Актуализира запис, съответстващ на префикса на pubkey. Битовете за разрешения варират според ролята на firmware, но долните 2 бита са: 0 (Гост), 1 (Само четене), 2 (Четене и писане), 3 (Администратор).", + "repeater_cliHelpGetBridgeType": "Получава тип мост none, rs232, espnow", + "repeater_cliHelpLogStart": "Започва записване на пакети във файловата система.", + "repeater_cliHelpLogStop": "Спира записването на пакети във файловата система.", + "repeater_cliHelpLogErase": "Изтрива логовете от пакета от файловата система.", + "repeater_cliHelpNeighbors": "Показва списък с други възли на репитер, чути чрез нулев хоп реклами. Всяка линия е id-prefix-hex:timestamp:snr-times-4", + "repeater_cliHelpNeighborRemove": "Премахва първия съвпадащ запис (по префикси на pubkey (hex)) от списъка с съседи.", + "repeater_cliHelpRegion": "(сериен режим) Изброява всички дефинирани региони и текущите разрешения за наводнения.", + "repeater_cliHelpRegionLoad": "Забележка: това е специално многокомандно извикване. Всяка следваща команда е име на регион (отстъпен с интервали, за да се покаже йерархията, с минимум един интервал). Завършва се чрез изпращане на празен ред/команда.", + "repeater_cliHelpRegionGet": "Търси регион с даден префикс на име (или \"\" за глобалния обхват). Отговаря с \"-> region-name (parent-name) 'F'\"", + "repeater_cliHelpRegionPut": "Добавя или актуализира дефиниция на регион с дадено име.", + "repeater_cliHelpRegionRemove": "Премахва дефиниция на регион с дадено име. (трябва да съвпада точно и да няма подрегиони)", + "repeater_cliHelpRegionAllowf": "Задава 'Потоп' разрешение за посочената област. ('' за глобалния/стария обхват)", + "repeater_cliHelpRegionDenyf": "Премахва разрешението \"F\"лоуд за посочената област. (ЗАБЕЛЕЖКА: в момента не се препоръчва да се използва на глобалното/старото ниво!! )", + "repeater_cliHelpRegionHome": "Отговаря с текущия 'home' регион. (Забележка: не е приложена никъде, запазена за бъдещи нужди).", + "repeater_cliHelpRegionHomeSet": "Задава 'домашно' региона.", + "repeater_cliHelpRegionSave": "Запазва списъка/картата с региони в съхранение.", + "repeater_cliHelpGps": "Показва статуса на GPS. Когато GPS е изключен, отговаря само с \"off\", ако е включен отговаря с \"on\", статус, fix, брой на сателити.", + "repeater_cliHelpGpsOnOff": "Включва/Изключва GPS захранването.", + "repeater_cliHelpGpsSync": "Синхронизира времето на възела с GPS часовника.", + "repeater_cliHelpGpsSetLoc": "Задава координатите на нодата по GPS и запазва предпочитанията.", + "repeater_cliHelpGpsAdvert": "Предоставя конфигурацията на рекламата за местоположението на възела:\n- none: не включвайте местоположението в рекламите\n- share: споделяйте gps местоположението (от SensorManager)\n- prefs: рекламирайте местоположението, съхранено в предпочитанията", + "repeater_cliHelpGpsAdvertSet": "Задава конфигурация на обявите за местоположение.", + "repeater_commandsListTitle": "Списък с команди", + "repeater_commandsListNote": "ЗАБЕЛЕЖКА: за различните команди \"set ...\", също така съществува команда \"get ...\".", + "repeater_general": "Общо", + "repeater_settingsCategory": "Настройки", + "repeater_bridge": "Мост", + "repeater_logging": "Логване", + "repeater_neighborsRepeaterOnly": "Съседи (Само за повтаряне)", + "repeater_regionManagementRepeaterOnly": "Управление на региони (Само за повтарящ се канал)", + "repeater_regionNote": "Регионните команди са въведени, за да управляват дефинициите и разрешенията на регионите.", + "repeater_gpsManagement": "Управление на GPS", + "repeater_gpsNote": "GPS командата е въведена, за да управлява теми, свързани с местоположението.", + "telemetry_receivedData": "Получени телеметрични данни", + "telemetry_requestTimeout": "Заявката за телеметрия е прекъсната.", + "telemetry_errorLoading": "Грешка при зареждане на телеметрията: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "Няма налични данни за телеметрията.", + "telemetry_channelTitle": "Канал {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Батерия", + "telemetry_voltageLabel": "Напрежение", + "telemetry_mcuTemperatureLabel": "Температура на MCU", + "telemetry_temperatureLabel": "Температура", + "telemetry_currentLabel": "Текущо", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Пътеки пъзел", + "channelPath_viewMap": "Преглед на картата", + "channelPath_otherObservedPaths": "Други Наблюдавани Пътища", + "channelPath_repeaterHops": "Повтарящи се скокове", + "channelPath_noHopDetails": "Детайлите за пакета не са предоставени.", + "channelPath_messageDetails": "Подробности на съобщението", + "channelPath_senderLabel": "Изпращач", + "channelPath_timeLabel": "Време", + "channelPath_repeatsLabel": "Повтаря", + "channelPath_pathLabel": "Път {index}", + "channelPath_observedLabel": "Наблюдавано", + "channelPath_observedPathTitle": "Наблюдаван път {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "Няма данни за местоположение.", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Неизвестно", + "channelPath_floodPath": "Поливане", + "channelPath_directPath": "Директно", + "channelPath_observedZeroOf": "0 от {total} скокове", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} от {total} скокове", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Карта на пътя", + "channelPath_noRepeaterLocations": "Няма налични местоположения на повторителите за този път.", + "channelPath_primaryPath": "Път {index} (Основен)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Пътекино", + "channelPath_observedPathHeader": "Наблюдаван път", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "Няма налични детайли за този пакет.", + "channelPath_unknownRepeater": "Неизвестен повторител", + "listFilter_tooltip": "Филтрирайте и сортирайте", + "listFilter_sortBy": "Сортирай по", + "listFilter_latestMessages": "Последни съобщения", + "listFilter_heardRecently": "Слушано е наскоро", + "listFilter_az": "A-Z", + "listFilter_filters": "Филтри", + "listFilter_all": "Всички", + "listFilter_users": "Потребители", + "listFilter_repeaters": "Повторители", + "listFilter_roomServers": "Сървъри на стая", + "listFilter_unreadOnly": "Само непрочетените", + "listFilter_newGroup": "Нова група" +} diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb new file mode 100644 index 0000000..9044962 --- /dev/null +++ b/lib/l10n/app_de.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "de", + "appTitle": "MeshCore Open", + "nav_contacts": "Kontakte", + "nav_channels": "Kanäle", + "nav_map": "Karte", + "common_cancel": "Abbrechen", + "common_connect": "Verbinden", + "common_unknownDevice": "Unbekanntes Gerät", + "common_save": "Speichern", + "common_delete": "Löschen", + "common_close": "Schließen", + "common_edit": "Bearbeiten", + "common_add": "Hinzufügen", + "common_settings": "Einstellungen", + "common_disconnect": "Trennen", + "common_connected": "Verbunden", + "common_disconnected": "Getrennt", + "common_create": "Erstellen", + "common_continue": "Fortfahren", + "common_share": "Teilen", + "common_copy": "Kopieren", + "common_retry": "Versuchen", + "common_hide": "Ausblenden", + "common_remove": "Löschen", + "common_enable": "Aktivieren", + "common_disable": "Deaktivieren", + "common_reboot": "Neustart", + "common_loading": "Laden...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Scannen nach Geräten...", + "scanner_connecting": "Verbunden...", + "scanner_disconnecting": "Trenne...", + "scanner_notConnected": "Nicht verbunden", + "scanner_connectedTo": "Verbunden mit {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Suche nach MeshCore-Geräten...", + "scanner_tapToScan": "Tippen Sie auf Scan, um MeshCore-Geräte zu finden.", + "scanner_connectionFailed": "Verbindungsfehler: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Stopp", + "scanner_scan": "Scannen", + "device_quickSwitch": "Schneller Umschalten", + "device_meshcore": "MeshCore", + "settings_title": "Einstellungen", + "settings_deviceInfo": "Geräteinformationen", + "settings_appSettings": "App-Einstellungen", + "settings_appSettingsSubtitle": "Benachrichtigungen, Messaging und Kartenwahrnehmungen", + "settings_nodeSettings": "Knoten-Einstellungen", + "settings_nodeName": "Knotenname", + "settings_nodeNameNotSet": "Nicht festgelegt", + "settings_nodeNameHint": "Gib den Knotenamen ein", + "settings_nodeNameUpdated": "Name aktualisiert", + "settings_radioSettings": "Funk Einstellungen", + "settings_radioSettingsSubtitle": "Frequenz, Leistung, Verbreitungsfaktor", + "settings_radioSettingsUpdated": "Funkparameter aktualisiert", + "settings_location": "Ort", + "settings_locationSubtitle": "GPS-Koordinaten", + "settings_locationUpdated": "Ort aktualisiert", + "settings_locationBothRequired": "Bitte geben Sie sowohl Breite als auch Längengrad ein.", + "settings_locationInvalid": "Ungültige Breiten- oder Längengrade.", + "settings_latitude": "Breitengrad", + "settings_longitude": "Längengrad", + "settings_privacyMode": "Privatschutzzustand", + "settings_privacyModeSubtitle": "Verstecken Sie Name/Ort in Anzeigen", + "settings_privacyModeToggle": "Aktivieren Sie den Datenschutzzustand, um Ihren Namen und Ihre Standortdaten in Anzeigen zu verbergen.", + "settings_privacyModeEnabled": "Privatschutzzustand aktiviert", + "settings_privacyModeDisabled": "Datenschutzmodus deaktiviert", + "settings_actions": "Aktionen", + "settings_sendAdvertisement": "Senden Sie Anzeige", + "settings_sendAdvertisementSubtitle": "Sendungsstatus jetzt", + "settings_advertisementSent": "Anzeige gesendet", + "settings_syncTime": "Synchronisierungszeit", + "settings_syncTimeSubtitle": "Stelle die Gerätewielfalt auf die Uhrzeit des Telefons ein", + "settings_timeSynchronized": "Zeit synchronisiert", + "settings_refreshContacts": "Kontakte aktualisieren", + "settings_refreshContactsSubtitle": "Kontakte-Liste vom Gerät neu laden", + "settings_rebootDevice": "Gerät neu starten", + "settings_rebootDeviceSubtitle": "MeshCore-Gerät neu starten", + "settings_rebootDeviceConfirm": "Sind Sie sicher, dass Sie das Gerät neu starten möchten? Sie werden getrennt.", + "settings_debug": "Fehlerbehebung", + "settings_bleDebugLog": "BLE-Debug-Protokoll", + "settings_bleDebugLogSubtitle": "BLE-Befehle, Antworten und Rohdaten", + "settings_appDebugLog": "App-Debug-Protokoll", + "settings_appDebugLogSubtitle": "Anwendung Debug-Nachrichten", + "settings_about": "Über", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "MeshCore Open Source Projekt 2026", + "settings_aboutDescription": "Ein Open-Source-Flutter-Client für MeshCore LoRa-Meshnetzwerkgeräte.", + "settings_infoName": "Name", + "settings_infoId": "ID", + "settings_infoStatus": "Status", + "settings_infoBattery": "Akku", + "settings_infoPublicKey": "Öffentlicher Schlüssel", + "settings_infoContactsCount": "Kontakte Anzahl", + "settings_infoChannelCount": "Kanalanzahl", + "settings_presets": "Voreinstellungen", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Frequenz (MHz)", + "settings_frequencyHelper": "300,00 - 2.500,00", + "settings_frequencyInvalid": "Ungültige Frequenz (300-2500 MHz)", + "settings_bandwidth": "Bandbreite", + "settings_spreadingFactor": "Verteilungsfaktor", + "settings_codingRate": "Programmierpauschale", + "settings_txPower": "TX-Leistung (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Ungültige TX-Leistung (0-22 dBm)", + "settings_longRange": "Langreich", + "settings_fastSpeed": "Schnelle Geschwindigkeit", + "settings_error": "Fehler: {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "App-Einstellungen", + "appSettings_appearance": "Aussehen", + "appSettings_theme": "Theme", + "appSettings_themeSystem": "Systemstandard", + "appSettings_themeLight": "Helligkeit", + "appSettings_themeDark": "Dunkel", + "appSettings_language": "Sprache", + "appSettings_languageSystem": "Systemstandard", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Benachrichtigungen", + "appSettings_enableNotifications": "Benachrichtigungen aktivieren", + "appSettings_enableNotificationsSubtitle": "Erhalte Benachrichtigungen für Nachrichten und Anzeigen", + "appSettings_notificationPermissionDenied": "Erlaubnis zur Benachrichtigung verweigert", + "appSettings_notificationsEnabled": "Benachrichtigungen aktiviert", + "appSettings_notificationsDisabled": "Benachrichtigungen deaktiviert", + "appSettings_messageNotifications": "Nachrichtenbenachrichtigungen", + "appSettings_messageNotificationsSubtitle": "Zeige Benachrichtigung beim Empfang neuer Nachrichten", + "appSettings_channelMessageNotifications": "Kanal-Nachrichten-Benachrichtigungen", + "appSettings_channelMessageNotificationsSubtitle": "Zeige Benachrichtigung beim Empfangen von Kanalnachrichten", + "appSettings_advertisementNotifications": "Werbeanzeigenbenachrichtigungen", + "appSettings_advertisementNotificationsSubtitle": "Zeige Benachrichtigung, wenn neue Knoten entdeckt werden.", + "appSettings_messaging": "Nachrichten", + "appSettings_clearPathOnMaxRetry": "Klares Pfad bei Max Wiederholungsversuch", + "appSettings_clearPathOnMaxRetrySubtitle": "Zurücksetzen des Kontaktpfads nach 5 fehlgeschlagenen Sendeverboten", + "appSettings_pathsWillBeCleared": "Die Pfade werden nach 5 fehlgeschlagenen Versuchen gelöscht.", + "appSettings_pathsWillNotBeCleared": "Die Pfade werden nicht automatisch gelöscht.", + "appSettings_autoRouteRotation": "Automatische Routenrotation", + "appSettings_autoRouteRotationSubtitle": "Wechseln zwischen den besten Pfaden und dem Fluten", + "appSettings_autoRouteRotationEnabled": "Automatische Routenrotation aktiviert", + "appSettings_autoRouteRotationDisabled": "Automatische Routenrotation deaktiviert", + "appSettings_battery": "Akku", + "appSettings_batteryChemistry": "Batteriechemie", + "appSettings_batteryChemistryPerDevice": "Konfiguriert pro Gerät ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Verbinde ein Gerät, um zu wählen", + "appSettings_batteryNmc": "18650 NMC (3,0–4,2 V)", + "appSettings_batteryLifepo4": "LiFePO4 (2,6–3,65 V)", + "appSettings_batteryLipo": "LiPo (3,0–4,2V)", + "appSettings_mapDisplay": "Kartendarstellung", + "appSettings_showRepeaters": "Zeige Repeater", + "appSettings_showRepeatersSubtitle": "Zeige Repeater-Knoten auf der Karte an", + "appSettings_showChatNodes": "Zeige Chat-Knoten", + "appSettings_showChatNodesSubtitle": "Chat-Knoten auf der Karte anzeigen", + "appSettings_showOtherNodes": "Zeige andere Knoten", + "appSettings_showOtherNodesSubtitle": "Andere Knotentypen auf der Karte anzeigen", + "appSettings_timeFilter": "Zeitfilter", + "appSettings_timeFilterShowAll": "Alle Knoten anzeigen", + "appSettings_timeFilterShowLast": "Zeige Knoten der letzten {hours} Stunden an", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Kartent Zeitfilter", + "appSettings_showNodesDiscoveredWithin": "Zeige Knoten, die innerhalb von:", + "appSettings_allTime": "Alle Zeit", + "appSettings_lastHour": "Letzter Stunde", + "appSettings_last6Hours": "Letzte 6 Stunden", + "appSettings_last24Hours": "Letzte 24 Stunden", + "appSettings_lastWeek": "Letzte Woche", + "appSettings_offlineMapCache": "Offline-Karten-Cache", + "appSettings_noAreaSelected": "Kein Bereich ausgewählt", + "appSettings_areaSelectedZoom": "Ausgewählte Fläche (Zoom {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Fehlerbehebung", + "appSettings_appDebugLogging": "App-Debug-Protokollierung", + "appSettings_appDebugLoggingSubtitle": "Protokolliere App-Debug-Nachrichten zur Fehlerbehebung", + "appSettings_appDebugLoggingEnabled": "App-Debug-Protokollierung aktiviert", + "appSettings_appDebugLoggingDisabled": "App-Debug-Protokollierung deaktiviert", + "contacts_title": "Kontakte", + "contacts_noContacts": "No Contacts noch", + "contacts_contactsWillAppear": "Kontakte werden angezeigt, wenn Geräte Werbung machen.", + "contacts_searchContacts": "Suche Kontakte...", + "contacts_noUnreadContacts": "Keine ungeklärten Kontakte", + "contacts_noContactsFound": "Keine Kontakte oder Gruppen gefunden.", + "contacts_deleteContact": "Löschen Sie Kontakt", + "contacts_removeConfirm": "Entfernen {contactName} aus den Kontakten?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Wiederholung verwalten", + "contacts_roomLogin": "Raum-Login", + "contacts_openChat": "Öffnen Sie Chat", + "contacts_editGroup": "Gruppen bearbeiten", + "contacts_deleteGroup": "Löschen Gruppe", + "contacts_deleteGroupConfirm": "Löschen Sie \"{groupName}\"?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Neue Gruppe", + "contacts_groupName": "Gruppenname", + "contacts_groupNameRequired": "Der Gruppennamen ist erforderlich.", + "contacts_groupAlreadyExists": "Die Gruppe \"{name}\" existiert bereits.", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Filtert Kontakte...", + "contacts_noContactsMatchFilter": "Keine Kontakte passen zu Ihrem Filter", + "contacts_noMembers": "Keine Mitglieder", + "contacts_lastSeenNow": "Letztes Ansehen jetzt", + "contacts_lastSeenMinsAgo": "Letzte Sichtung {minutes} Minuten her.", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Letzte Sichtung vor 1 Stunde.", + "contacts_lastSeenHoursAgo": "Letzte Aktivität vor {hours} Stunden.", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Letzte Sichtung vor 1 Tag", + "contacts_lastSeenDaysAgo": "Letzte Sichtung {days} Tage zuvor", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Kanäle", + "channels_noChannelsConfigured": "Keine Kanäle konfiguriert", + "channels_addPublicChannel": "Öffentlichen Kanal hinzufügen", + "channels_searchChannels": "Suche Kanäle...", + "channels_noChannelsFound": "Keine Kanäle gefunden", + "channels_channelIndex": "Kanal {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Hashtag-Kanal", + "channels_public": "Öffentlich", + "channels_private": "Privat", + "channels_publicChannel": "Öffentlicher Kanal", + "channels_privateChannel": "Privater Kanal", + "channels_editChannel": "Kanal bearbeiten", + "channels_deleteChannel": "Löschen Sie Kanal", + "channels_deleteChannelConfirm": "Löschen \"{name}\"? Dies kann nicht rückgängig gemacht werden.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Kanal \"{name}\" gelöscht", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Kanal hinzufügen", + "channels_channelIndexLabel": "Kanalindex", + "channels_channelName": "Kanalname", + "channels_usePublicChannel": "Verwende öffentlichen Kanal", + "channels_standardPublicPsk": "Standard-Öffentliche PSK", + "channels_pskHex": "PSK (Hex)", + "channels_generateRandomPsk": "Zufällige PSK generieren", + "channels_enterChannelName": "Bitte geben Sie einen Kanalnamen ein.", + "channels_pskMustBe32Hex": "Die PSK muss 32 hexadezimale Zeichen haben.", + "channels_channelAdded": "Kanal \"{name}\" hinzugefügt", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Bearbeiteten Kanal {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "SMAZ-Komprimierung", + "channels_channelUpdated": "Kanal \"{name}\" aktualisiert", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "Öffentlicher Kanal hinzugefügt", + "channels_sortBy": "Sortiere nach", + "channels_sortManual": "Manuelle", + "channels_sortAZ": "A bis Z", + "channels_sortLatestMessages": "Letzte Nachrichten", + "channels_sortUnread": "Unlescht", + "chat_noMessages": "Noch keine Nachrichten.", + "chat_sendMessageToStart": "Eine Nachricht senden, um anzufangen.", + "chat_originalMessageNotFound": "Originalmeldung nicht gefunden", + "chat_replyingTo": "Antworten an {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Antworten Sie {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Ort", + "chat_sendMessageTo": "Sende eine Nachricht an {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Eine Nachricht eingeben...", + "chat_messageTooLong": "Nachricht ist zu lang (max {maxBytes} Bytes).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Nachricht kopiert", + "chat_messageDeleted": "Nachricht gelöscht", + "chat_retryingMessage": "Versuche es erneut.", + "chat_retryCount": "Versuchen {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "GIF senden", + "chat_reply": "Beantworten", + "chat_addReaction": "Reaktion hinzufügen", + "chat_me": "Ich", + "emojiCategorySmileys": "Emoticons", + "emojiCategoryGestures": "Gesten", + "emojiCategoryHearts": "Herz", + "emojiCategoryObjects": "Objekte", + "gifPicker_title": "Wähle ein GIF", + "gifPicker_searchHint": "Suche nach GIFs...", + "gifPicker_poweredBy": "Angetrieben von GIPHY", + "gifPicker_noGifsFound": "Keine GIFs gefunden", + "gifPicker_failedLoad": "GIF-Dateien konnten nicht geladen werden.", + "gifPicker_failedSearch": "Suche nach GIFs fehlgeschlagen", + "gifPicker_noInternet": "Keine Internetverbindung", + "debugLog_appTitle": "App-Debug-Protokoll", + "debugLog_bleTitle": "BLE-Debug-Protokoll", + "debugLog_copyLog": "Kopieren Sie Protokoll", + "debugLog_clearLog": "Log löschen", + "debugLog_copied": "Debug-Protokoll kopiert", + "debugLog_bleCopied": "BLE-Protokoll kopiert", + "debugLog_noEntries": "No Debug-Protokolle noch verfügbar", + "debugLog_enableInSettings": "Aktivieren Sie das App-Debug-Logging in den Einstellungen", + "debugLog_frames": "Rahmen", + "debugLog_rawLogRx": "Roh-Log-RX", + "debugLog_noBleActivity": "No BLE-Aktivität bisher", + "debugFrame_length": "Rahmenlänge: {count} Bytes", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Befehl: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Textnachricht-Frame:", + "debugFrame_destinationPubKey": "- Ziel-Pub-Schlüssel: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Zeitstempel: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Flags: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- Textart: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Einfach", + "debugFrame_text": "- Text: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Hex-Dump:", + "chat_pathManagement": "Pfadverwaltung", + "chat_routingMode": "Routenmodus", + "chat_autoUseSavedPath": "Automatisch (gespeicherten Pfad verwenden)", + "chat_forceFloodMode": "Zwangsgelände-Modus erzwingen", + "chat_recentAckPaths": "Aktuelle ACK-Pfade (tasten, um zu verwenden):", + "chat_pathHistoryFull": "Die Pfadhistorie ist voll. Entferne Einträge, um neue hinzuzufügen.", + "chat_hopSingular": "Springe", + "chat_hopPlural": "Hops", + "chat_hopsCount": "{count} {count, plural, =1{Hop} other{Hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "Erfolgreiche", + "chat_removePath": "Pfad entfernen", + "chat_noPathHistoryYet": "Noe eine Pfadhistorie vorhanden.\nSende eine Nachricht, um Pfade zu entdecken.", + "chat_pathActions": "Pfadaktionen:", + "chat_setCustomPath": "Lege benutzerdefinierten Pfad fest", + "chat_setCustomPathSubtitle": "Manuelle Routenpfad festlegen", + "chat_clearPath": "Klares Pfad", + "chat_clearPathSubtitle": "Zwinge bei nächster Sendung eine erneute Entdeckung durch.", + "chat_pathCleared": "Pfad freigelegt. Nächste Nachricht wird Route neu entdecken.", + "chat_floodModeSubtitle": "Verwende den Routingschalter in der App-Leiste", + "chat_floodModeEnabled": "Flutmodus aktiviert. Über den Routing-Icon in der App-Leiste wieder aktivieren.", + "chat_fullPath": "Vollständiger Pfad", + "chat_pathDetailsNotAvailable": "Die Pfaddetails sind noch nicht verfügbar. Versuchen Sie, eine Nachricht zu senden, um zu aktualisieren.", + "chat_pathSetHops": "Pfad gesetzt: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Gespeichert lokal. Mit Verbinden zum Synchronisieren.", + "chat_pathDeviceConfirmed": "Gerät bestätigt.", + "chat_pathDeviceNotConfirmed": "Gerät noch nicht bestätigt.", + "chat_type": "Gib ein", + "chat_path": "Pfad", + "chat_publicKey": "Öffentlicher Schlüssel", + "chat_compressOutgoingMessages": "Komprimieren ausgehende Nachrichten", + "chat_floodForced": "Überschwemmung (erzwungen)", + "chat_directForced": "Direkt (gezwungen)", + "chat_hopsForced": "{count} Sprünge (erzwungen)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Überschwemmung (automatisch)", + "chat_direct": "Direkt", + "chat_poiShared": "Gemeinsamer POI", + "chat_unread": "Unlescht: {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Knotenkarte", + "map_noNodesWithLocation": "Keine Knoten mit Standortdaten", + "map_nodesNeedGps": "Knoten müssen ihre GPS-Koordinaten\nteilen,\num auf der Karte\nerscheinen.", + "map_nodesCount": "Knoten: {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Pins: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Chat", + "map_repeater": "Wiederholung", + "map_room": "Raum", + "map_sensor": "Sensor", + "map_pinDm": "Sperren (DM)", + "map_pinPrivate": "Privat-Pin", + "map_pinPublic": "Öffentliche Taste (PIN)", + "map_lastSeen": "Letzte Sichtung", + "map_disconnectConfirm": "Sind Sie sicher, dass Sie sich von diesem Gerät trennen möchten?", + "map_from": "Von", + "map_source": "Quelle", + "map_flags": "Flaggen", + "map_shareMarkerHere": "Teilen Sie hier das Marker.", + "map_pinLabel": "Kennzeichnungslabel", + "map_label": "Label", + "map_pointOfInterest": "Punkt von Interesse", + "map_sendToContact": "Senden an Kontakt", + "map_sendToChannel": "Senden Sie Kanal", + "map_noChannelsAvailable": "Keine Kanäle verfügbar", + "map_publicLocationShare": "Öffentliche Standortfreigabe", + "map_publicLocationShareConfirm": "Sie werden kurz darauf einen Ort in {channelLabel} teilen. Dieser Kanal ist öffentlich und jeder mit dem PSK kann ihn sehen.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Verbinde ein Gerät, um Marker zu teilen", + "map_filterNodes": "Filter Knoten", + "map_nodeTypes": "Knotentypen", + "map_chatNodes": "Chat-Knoten", + "map_repeaters": "Wiederholer", + "map_otherNodes": "Andere Knoten", + "map_keyPrefix": "Schlüsselpräfix", + "map_filterByKeyPrefix": "Filter nach Schlüsselpräfix", + "map_publicKeyPrefix": "Öffentlicher Schlüsselpräfix", + "map_markers": "Marker", + "map_showSharedMarkers": "Zeige gemeinsam genutzte Marker", + "map_lastSeenTime": "Letzte Sichtung", + "map_sharedPin": "Gemeinsames Passwort", + "map_joinRoom": "Beitreten Sie dem Raum", + "map_manageRepeater": "Wiederholung verwalten", + "mapCache_title": "Offline-Karten-Cache", + "mapCache_selectAreaFirst": "Wählen Sie zuerst einen Bereich zum Zwischenspeichern aus.", + "mapCache_noTilesToDownload": "Keine Tiles für diese Region zum Herunterladen verfügbar.", + "mapCache_downloadTilesTitle": "Herunterladen von Tiles", + "mapCache_downloadTilesPrompt": "Laden {count} Tiles für den Offline-Bereich herunter?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Herunterladen", + "mapCache_cachedTiles": "Zwischengespeicherte {count} Fliesen", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Zwischengespeicherte {downloaded} Tiles ({failed} fehlgeschlagen)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Leeren Offline-Cache", + "mapCache_clearOfflineCachePrompt": "Alle zwischengespeicherten Kartenraster entfernen?", + "mapCache_offlineCacheCleared": "Offline-Cache gelöscht", + "mapCache_noAreaSelected": "Kein Bereich ausgewählt", + "mapCache_cacheArea": "Zwischenspeicherbereich", + "mapCache_useCurrentView": "Aktuelle Ansicht verwenden", + "mapCache_zoomRange": "Zoom Bereich", + "mapCache_estimatedTiles": "Geschätzte Fliesen: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Heruntergeladen {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Herunterladen von Tiles", + "mapCache_clearCacheButton": "Cache leeren", + "mapCache_failedDownloads": "Fehlgeschlagene Downloads: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Gerade eben", + "time_minutesAgo": "{minutes} Minuten her", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours} Stunden her", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} Tage/Tage zuvor", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "Stunde", + "time_hours": "Stunden", + "time_day": "Tag", + "time_days": "Tage", + "time_week": "Woche", + "time_weeks": "Wochen", + "time_month": "Monat", + "time_months": "Monate", + "time_minutes": "Minuten", + "time_allTime": "Alle Zeit", + "dialog_disconnect": "Trennen", + "dialog_disconnectConfirm": "Sind Sie sicher, dass Sie sich von diesem Gerät trennen möchten?", + "login_repeaterLogin": "Wiederholungseingang anmelden", + "login_roomLogin": "Raum-Login", + "login_password": "Passwort", + "login_enterPassword": "Passwort eingeben", + "login_savePassword": "Passwort speichern", + "login_savePasswordSubtitle": "Das Passwort wird auf diesem Gerät sicher gespeichert.", + "login_repeaterDescription": "Geben Sie das Repeater-Passwort ein, um auf Einstellungen und Status zuzugreifen.", + "login_roomDescription": "Geben Sie das Raumkennwort ein, um auf die Einstellungen und den Status zuzugreifen.", + "login_routing": "Routen", + "login_routingMode": "Routenmodus", + "login_autoUseSavedPath": "Automatisch (gespeicherten Pfad verwenden)", + "login_forceFloodMode": "Zwangsgelände-Modus erzwingen", + "login_managePaths": "Pfadverwaltung", + "login_login": "Anmelden", + "login_attempt": "Versuche {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Anmeldung fehlgeschlagen: {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Neu laden", + "common_clear": "Löschen", + "path_currentPath": "Aktiger Pfad: {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Verwenden Sie {count} {count, plural, =1{Hop} other{Hops}} Pfad", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Gib Pfad an", + "path_currentPathLabel": "Aktueller Pfad", + "path_hexPrefixInstructions": "Gib für jeden Hopfen 2-stellige Hex-Präfixe ein, getrennt durch Kommas.", + "path_hexPrefixExample": "Beispiel: A1,F2,3C (jeder Knoten verwendet den ersten Byte seines öffentlichen Schlüssels)", + "path_labelHexPrefixes": "Pfad (Hex-Präfixe)", + "path_helperMaxHops": "Max 64 Sprünge. Jede Präfixe ist 2 Hexadezimalzeichen (1 Byte)", + "path_selectFromContacts": "Oder wähle aus Kontakten aus:", + "path_noRepeatersFound": "Keine Repeater oder Raumserver gefunden.", + "path_customPathsRequire": "Benutzerdefinierte Pfade erfordern Zwischen-Hops, die Nachrichten weiterleiten können.", + "path_invalidHexPrefixes": "Ungültige Hexadezimal-Präfixe: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "Pfad zu lang. Maximal 64 Hops erlaubt.", + "path_setPath": "Pfad festlegen", + "repeater_management": "Wiederholungselement-Verwaltung", + "repeater_managementTools": "Verwaltungs-Tools", + "repeater_status": "Status", + "repeater_statusSubtitle": "Status, Statistiken und Nachbarn anzeigen", + "repeater_telemetry": "Telemetrie", + "repeater_telemetrySubtitle": "Sensordaten und Systemwerte anzeigen", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Sende Befehle an den Repeater", + "repeater_settings": "Einstellungen", + "repeater_settingsSubtitle": "Wiederholungsparameter konfigurieren", + "repeater_statusTitle": "Wiederholungszustand", + "repeater_routingMode": "Routenmodus", + "repeater_autoUseSavedPath": "Automatisch (gespeicherten Pfad verwenden)", + "repeater_forceFloodMode": "Zwangsgelände-Modus erzwingen", + "repeater_pathManagement": "Pfadverwaltung", + "repeater_refresh": "Aktualisieren", + "repeater_statusRequestTimeout": "Statusanfrage zeitweise fehlgeschlagen.", + "repeater_errorLoadingStatus": "Fehler beim Laden des Status: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Systeminformation", + "repeater_battery": "Akku", + "repeater_clockAtLogin": "Uhr (bei Anmeldung)", + "repeater_uptime": "Verfügbarkeit", + "repeater_queueLength": "Warteschlangenlänge", + "repeater_debugFlags": "Fehlerbehebungsoptionen", + "repeater_radioStatistics": "Funk-Statistik", + "repeater_lastRssi": "Letzter RSSI", + "repeater_lastSnr": "Letzter SNR", + "repeater_noiseFloor": "Rauschpegel", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Paketstatistiken", + "repeater_sent": "Gesendet", + "repeater_received": "Empfangen", + "repeater_duplicates": "Duplikate", + "repeater_daysHoursMinsSecs": "{days} Tage {hours}h {minutes}m {seconds}s", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Gesamt: {total}, Flut: {flood}, Direkt: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Gesamt: {total}, Flut: {flood}, Direkt: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Überflut: {flood}, Direkt: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Gesamt: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Wiederholungseinstellungen", + "repeater_basicSettings": "Grundlegende Einstellungen", + "repeater_repeaterName": "Wiederholungseintrag", + "repeater_repeaterNameHelper": "Anzeigename für diesen Repeater", + "repeater_adminPassword": "Admin-Passwort", + "repeater_adminPasswordHelper": "Vollzugriffspasswort", + "repeater_guestPassword": "Gast-Passwort", + "repeater_guestPasswordHelper": "Schreibgeschützter Zugriffspasswort", + "repeater_radioSettings": "Funk Einstellungen", + "repeater_frequencyMhz": "Frequenz (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Power", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Bandbreite", + "repeater_spreadingFactor": "Verteilungsfaktor", + "repeater_codingRate": "Programmierpauschale", + "repeater_locationSettings": "Standort Einstellungen", + "repeater_latitude": "Breitengrad", + "repeater_latitudeHelper": "Dezimalgrad (z.B. 37,7749)", + "repeater_longitude": "Längengrad", + "repeater_longitudeHelper": "Dezimalgrad (z.B. -122,4194)", + "repeater_features": "Funktionen", + "repeater_packetForwarding": "Paketweiterleitung", + "repeater_packetForwardingSubtitle": "Aktivieren Sie den Repeater, um Pakete weiterzuleiten.", + "repeater_guestAccess": "Gastzugriff", + "repeater_guestAccessSubtitle": "Gast-Zugriff mit beschränkten Rechten zulassen", + "repeater_privacyMode": "Privatschutzzustand", + "repeater_privacyModeSubtitle": "Verstecken Sie Name/Ort in Anzeigen", + "repeater_advertisementSettings": "Werbe Einstellungen", + "repeater_localAdvertInterval": "Lokaler Werbeintervall", + "repeater_localAdvertIntervalMinutes": "{minutes} Minuten", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Überschwemmungsanzeige-Intervall", + "repeater_floodAdvertIntervalHours": "{hours} Stunden", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Verschlüsselte Werbeintervall", + "repeater_dangerZone": "Gefahrenzone", + "repeater_rebootRepeater": "Neustart Repeater", + "repeater_rebootRepeaterSubtitle": "Wiederholen Sie das Repeater-Gerät.", + "repeater_rebootRepeaterConfirm": "Sind Sie sicher, dass Sie diesen Repeater neu starten möchten?", + "repeater_regenerateIdentityKey": "Schlüssel für die Identitätswiederherstellung", + "repeater_regenerateIdentityKeySubtitle": "Neuen öffentlichen/privaten Schlüsselpaar generieren", + "repeater_regenerateIdentityKeyConfirm": "Dies generiert eine neue Identität für den Repeater. Fortfahren?", + "repeater_eraseFileSystem": "Dateisystem löschen", + "repeater_eraseFileSystemSubtitle": "Formatiere die Repeater-Dateisystemdatei", + "repeater_eraseFileSystemConfirm": "WARNUNG: Dies löscht alle Daten auf dem Repeater. Dies kann nicht rückgängig gemacht werden!", + "repeater_eraseSerialOnly": "Löschen ist nur über die serielle Konsole möglich.", + "repeater_commandSent": "Befehl gesendet: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Fehler beim Senden des Befehls: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "Bestätigen", + "repeater_settingsSaved": "Einstellungen erfolgreich gespeichert", + "repeater_errorSavingSettings": "Fehler beim Speichern der Einstellungen: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Grundlegende Einstellungen aktualisieren", + "repeater_refreshRadioSettings": "Radio-Einstellungen aktualisieren", + "repeater_refreshTxPower": "Batterie-Strom aktualisieren", + "repeater_refreshLocationSettings": "Aktualisieren Sie die Standort Einstellungen", + "repeater_refreshPacketForwarding": "Aktualisieren Paketweiterleitung", + "repeater_refreshGuestAccess": "Aktualisieren Sie den Gastzugriff", + "repeater_refreshPrivacyMode": "Wiederherstellen des Datenschutzzustands", + "repeater_refreshAdvertisementSettings": "Aktualisieren Sie die Werbe Einstellungen", + "repeater_refreshed": "{label} wurde aktualisiert", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Fehler beim Aktualisieren von {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Wiederholung CLI", + "repeater_debugNextCommand": "Fehlersuche Nächster Befehl", + "repeater_commandHelp": "Hilfe", + "repeater_clearHistory": "Löschung der Historie", + "repeater_noCommandsSent": "Noch keine Befehle gesendet.", + "repeater_typeCommandOrUseQuick": "Geben Sie einen Befehl unten ein oder verwenden Sie Schnellbefehle", + "repeater_enterCommandHint": "Geben Sie den Befehl ein...", + "repeater_previousCommand": "Vorhergehende Aktion", + "repeater_nextCommand": "Nächste Aktion", + "repeater_enterCommandFirst": "Geben Sie zuerst einen Befehl ein", + "repeater_cliCommandFrameTitle": "CLI-Befehlsfenster", + "repeater_cliCommandError": "Fehler: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Name erhalten", + "repeater_cliQuickGetRadio": "Radio empfangen", + "repeater_cliQuickGetTx": "Erhalte TX", + "repeater_cliQuickNeighbors": "Nachbarn", + "repeater_cliQuickVersion": "Version", + "repeater_cliQuickAdvertise": "Werben", + "repeater_cliQuickClock": "Uhr", + "repeater_cliHelpAdvert": "Sendet ein Werbepaket", + "repeater_cliHelpReboot": "Startet das Gerät neu. (Beachten Sie, dass es möglicherweise zu einer 'Timeout'-Situation kommt, was normal ist.)", + "repeater_cliHelpClock": "Zeigt die aktuelle Uhrzeit pro Gerät an.", + "repeater_cliHelpPassword": "Legt ein neues Administrator-Passwort für das Gerät fest.", + "repeater_cliHelpVersion": "Zeigt die Geräteversion und das Datum des Firmware-Builds an.", + "repeater_cliHelpClearStats": "Setzt verschiedene Statistikkalkulate auf Null zurück.", + "repeater_cliHelpSetAf": "Legt den Luftzeitfaktor fest.", + "repeater_cliHelpSetTx": "Legt die LoRa-Übertragungspower in dBm (bezogen auf 1 Watt) fest. (Neustart erforderlich, um die Änderungen anzuwenden)", + "repeater_cliHelpSetRepeat": "Aktiviert oder deaktiviert die Repeater-Rolle für diesen Knoten.", + "repeater_cliHelpSetAllowReadOnly": "(Raumspeicher) Wenn 'an', dann wird die Anmeldung mit einem leeren Passwort erlaubt sein, aber kann nicht in den Raum geschickt werden. (nur lesen möglich).", + "repeater_cliHelpSetFloodMax": "Legt die maximale Anzahl an Hops für Pakete der eingehenden Flut (wenn >= max, wird das Paket nicht weitergeleitet)", + "repeater_cliHelpSetIntThresh": "Legt den Interferenzeniveau (in dB) fest. Der Standardwert ist 14. Auf 0 setzen, um die Erkennung von Kanalinterferenzen zu deaktivieren.", + "repeater_cliHelpSetAgcResetInterval": "Legt das Intervall für das Zurücksetzen des Auto Gain Controllers fest. Auf 0 setzen, um die Funktion zu deaktivieren.", + "repeater_cliHelpSetMultiAcks": "Aktiviert oder deaktiviert die Funktion 'Doppel-ACKs'.", + "repeater_cliHelpSetAdvertInterval": "Legt das Timer-Intervall in Minuten fest, um ein lokales (ohne-Weiterleitung) Werbe-Paket zu senden. Auf 0 setzen, um die Funktion zu deaktivieren.", + "repeater_cliHelpSetFloodAdvertInterval": "Legt das Timer-Intervall in Stunden für den Versand eines Flut-Werbungspakets fest. Auf 0 setzen, um es zu deaktivieren.", + "repeater_cliHelpSetGuestPassword": "Legt/aktualisiert das Gastpasswort fest. (für Repeater können Gast-Logins die \"Get Stats\"-Anfrage senden)", + "repeater_cliHelpSetName": "Legt den Anzeigenamen fest.", + "repeater_cliHelpSetLat": "Legt die Breitengrad-Angabe der Werbekarte fest. (dezimale Grad)", + "repeater_cliHelpSetLon": "Legt die Längengrade der Werbe-Map fest. (dezimale Grad)", + "repeater_cliHelpSetRadio": "Legt komplett neue Radio-Parameter fest und speichert diese als Präferenzen. Benötigt einen \"Reboot\"-Befehl, um sie anzuwenden.", + "repeater_cliHelpSetRxDelay": "Sets (experimentell) als Basis (muss > 1 sein für den Effekt) zur Anwendung einer leichten Verzögerung bei empfangenen Paketen, basierend auf Signalstärke/Punktzahl. Auf 0 setzen, um die Funktion zu deaktivieren.", + "repeater_cliHelpSetTxDelay": "Legt einen Faktor fest, der mit der Zeit bei voller Zuluft für ein Flood-Mode-Paket und mit einem zufälligen Slot-System multipliziert wird, um dessen Weiterleitung zu verzögern (um Kollisionen zu vermeiden).", + "repeater_cliHelpSetDirectTxDelay": "Ähnlich wie txdelay, aber zum Anwenden einer zufälligen Verzögerung bei der Weiterleitung von Direktmodus-Paketen.", + "repeater_cliHelpSetBridgeEnabled": "Brücke aktivieren/deaktivieren.", + "repeater_cliHelpSetBridgeDelay": "Setze Verzögerung vor erneuter Übertragung von Paketen.", + "repeater_cliHelpSetBridgeSource": "Wählen Sie, ob die Brücke empfangene oder gesendete Pakete erneut übertragen soll.", + "repeater_cliHelpSetBridgeBaud": "Setze die serielle Link-Baudrate für RS232-Brücken.", + "repeater_cliHelpSetBridgeSecret": "Richte das Espnow-Brücken-Geheimnis ein.", + "repeater_cliHelpSetAdcMultiplier": "Legt einen benutzerdefinierten Faktor zur Anpassung der gemeldeten Batteriewirkspannung fest (nur auf ausgewählten Boards unterstützt).", + "repeater_cliHelpTempRadio": "Legt vorübergehende Funkparameter für die angegebene Anzahl von Minuten fest und kehrt anschließend zu den ursprünglichen Funkparametern zurück (wird nicht in den Einstellungen gespeichert).", + "repeater_cliHelpSetPerm": "Ändert die ACL. Entfernt das passende Eintragen (durch Pubkey-Präfix), wenn \"permissions\" auf 0 steht. Fügt ein neues Eintragen hinzu, wenn die Pubkey-Hex-Länge vollständig ist und nicht bereits in der ACL vorhanden ist. Aktualisiert das Eintragen anhand des übereinstimmenden Pubkey-Präfix. Berechtigungsbits variieren je nach Firmware-Rolle, aber die unteren 2 Bits sind: 0 (Gast), 1 (Nur Lesen), 2 (Lesen/Schreiben), 3 (Admin)", + "repeater_cliHelpGetBridgeType": "Ruft Brückentyp none, rs232, espnow ab.", + "repeater_cliHelpLogStart": "Beginnt die Paketprotokollierung in das Dateisystem.", + "repeater_cliHelpLogStop": "Stoppt das Paketprotokollieren in das Dateisystem.", + "repeater_cliHelpLogErase": "Löscht die Paketprotokolle aus dem Dateisystem.", + "repeater_cliHelpNeighbors": "Zeigt eine Liste anderer Repeater-Knoten an, die über Zero-Hop-Werbung gehört wurden. Jede Zeile ist id-prefix-hex:timestamp:snr-times-4", + "repeater_cliHelpNeighborRemove": "Entfernt das erste übereinstimmende Element (über Pubkey-Präfix (hex)) aus der Liste der Nachbarn.", + "repeater_cliHelpRegion": "(Serien nur) Listet alle definierten Regionen und aktuelle Hochwassermissungen auf.", + "repeater_cliHelpRegionLoad": "Hinweis: Dies ist ein spezieller Mehrbefehl-Aufruf. Jeder nachfolgende Befehl ist ein Regionsname (eingedruckt mit Leerzeichen zur Angabe der übergeordneten Hierarchie, mit mindestens einem Leerzeichen). Beendet durch das Senden einer Leerzeile/des Befehls.", + "repeater_cliHelpRegionGet": "Sucht die Region mit dem gegebenen Namenspräfix (oder \"\\\" für den globalen Scope) und antwortet mit \"-> region-name (parent-name) 'F'\".", + "repeater_cliHelpRegionPut": "Fügt eine Region-Definition mit dem angegebenen Namen hinzu oder aktualisiert diese.", + "repeater_cliHelpRegionRemove": "Löscht eine Regiondefinition mit dem angegebenen Namen. (muss genau übereinstimmen und keine Kindregionen haben)", + "repeater_cliHelpRegionAllowf": "Legt die 'Flut'-Berechtigung für die angegebene Region fest. ('' für den globalen/legacy-Bereich)", + "repeater_cliHelpRegionDenyf": "Entfernt die \"F\"lood-Berechtigung für die angegebene Region. (ANMERKUNG: in dieser Phase wird nicht empfohlen, dies auf dem globalen/legacy-Bereich zu verwenden!!)", + "repeater_cliHelpRegionHome": "Antwortet mit der aktuellen 'Home'-Region. (Hinweis wurde bisher nirgendwo angewendet, für zukünftige Zwecke reserviert)", + "repeater_cliHelpRegionHomeSet": "Legt die 'Home'-Region fest.", + "repeater_cliHelpRegionSave": "Speichert die Regionenliste/Karte in den Speicher.", + "repeater_cliHelpGps": "Zeigt GPS-Status an. Wenn GPS deaktiviert ist, antwortet es nur mit \"aus\", wenn es eingeschaltet ist, antwortet es mit \"an\", \"Status\", \"Fix\" und Satellitenanzahl.", + "repeater_cliHelpGpsOnOff": "Schaltet die GPS-Leistung ein/aus.", + "repeater_cliHelpGpsSync": "Synchronisiert die Knotenzeit mit der GPS-Uhr.", + "repeater_cliHelpGpsSetLoc": "Setze die Position des Knotens auf GPS-Koordinaten und speichere die Präferenzen.", + "repeater_cliHelpGpsAdvert": "Gibt Konfiguration für die Standortanzeige des Knotens:\n- none: Standort nicht in Anzeigen einbeziehen\n- share: GPS-Standort teilen (von SensorManager)\n- prefs: Standort aus Einstellungen anzeigen", + "repeater_cliHelpGpsAdvertSet": "Legt die Standort-Anzeigekonfiguration fest.", + "repeater_commandsListTitle": "Befehlsliste", + "repeater_commandsListNote": "ACHTUNG: Für die verschiedenen „set ...“-Befehle gibt es auch einen „get ...“-Befehl.", + "repeater_general": "Allgemein", + "repeater_settingsCategory": "Einstellungen", + "repeater_bridge": "Brücke", + "repeater_logging": "Protokollierung", + "repeater_neighborsRepeaterOnly": "Nachbarn (nur Repeater)", + "repeater_regionManagementRepeaterOnly": "Regionenverwaltung (nur Repeater)", + "repeater_regionNote": "Region-Befehle wurden eingeführt, um Region-Definitionen und Berechtigungen zu verwalten.", + "repeater_gpsManagement": "GPS-Verwaltung", + "repeater_gpsNote": "Der GPS-Befehl wurde eingeführt, um Standortbezogene Themen zu verwalten.", + "telemetry_receivedData": "Empfangene Telemetriedaten", + "telemetry_requestTimeout": "Telemetry-Anfrage hat zu lange gedauert.", + "telemetry_errorLoading": "Fehler beim Laden der Telemetrie: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "Keine Telemetriedaten verfügbar.", + "telemetry_channelTitle": "Kanal {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Akku", + "telemetry_voltageLabel": "Spannung", + "telemetry_mcuTemperatureLabel": "MCU Temperatur", + "telemetry_temperatureLabel": "Temperatur", + "telemetry_currentLabel": "Aktuell", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts} Volt", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Paketpfad", + "channelPath_viewMap": "Karte anzeigen", + "channelPath_otherObservedPaths": "Sonstige beobachtete Pfade", + "channelPath_repeaterHops": "Wiederholungs-Sprünge", + "channelPath_noHopDetails": "Die Detailangaben für dieses Paket sind nicht verfügbar.", + "channelPath_messageDetails": "Nachrichtsdetails", + "channelPath_senderLabel": "Sender", + "channelPath_timeLabel": "Zeit", + "channelPath_repeatsLabel": "Wiederholung", + "channelPath_pathLabel": "Pfad {index}", + "channelPath_observedLabel": "Beobachtet", + "channelPath_observedPathTitle": "Beobachteter Pfad {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "Keine Standortdaten", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Unbekannt", + "channelPath_floodPath": "Überschwemmung", + "channelPath_directPath": "Direkt", + "channelPath_observedZeroOf": "0 von {total} Sprüngen", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} von {total} Sprüngen", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Pfadkarte", + "channelPath_noRepeaterLocations": "Für diesen Pfad stehen keine Repeater-Positionen zur Verfügung.", + "channelPath_primaryPath": "Pfad {index} (Primär)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Pfad", + "channelPath_observedPathHeader": "Beobachteter Pfad", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "Keine Informationen zu dieser Paketroute verfügbar.", + "channelPath_unknownRepeater": "Unbekannter Repeater", + "listFilter_tooltip": "Filteren und sortieren", + "listFilter_sortBy": "Sortiere nach", + "listFilter_latestMessages": "Letzte Nachrichten", + "listFilter_heardRecently": "Hörte kürzlich", + "listFilter_az": "A-Z", + "listFilter_filters": "Filtere", + "listFilter_all": "Alle", + "listFilter_users": "Benutzer", + "listFilter_repeaters": "Wiederholer", + "listFilter_roomServers": "Raumserver", + "listFilter_unreadOnly": "Nur nicht gelesen", + "listFilter_newGroup": "Neue Gruppe" +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb new file mode 100644 index 0000000..dc53f73 --- /dev/null +++ b/lib/l10n/app_en.arb @@ -0,0 +1,1144 @@ +{ + "@@locale": "en", + + "appTitle": "MeshCore Open", + + "nav_contacts": "Contacts", + "nav_channels": "Channels", + "nav_map": "Map", + + "common_cancel": "Cancel", + "common_connect": "Connect", + "common_unknownDevice": "Unknown Device", + "common_save": "Save", + "common_delete": "Delete", + "common_close": "Close", + "common_edit": "Edit", + "common_add": "Add", + "common_settings": "Settings", + "common_disconnect": "Disconnect", + "common_connected": "Connected", + "common_disconnected": "Disconnected", + "common_create": "Create", + "common_continue": "Continue", + "common_share": "Share", + "common_copy": "Copy", + "common_retry": "Retry", + "common_hide": "Hide", + "common_remove": "Remove", + "common_enable": "Enable", + "common_disable": "Disable", + "common_reboot": "Reboot", + "common_loading": "Loading...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": {"type": "String"} + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": {"type": "int"} + } + }, + + "scanner_title": "MeshCore Open", + "scanner_scanning": "Scanning for devices...", + "scanner_connecting": "Connecting...", + "scanner_disconnecting": "Disconnecting...", + "scanner_notConnected": "Not connected", + "scanner_connectedTo": "Connected to {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": {"type": "String"} + } + }, + "scanner_searchingDevices": "Searching for MeshCore devices...", + "scanner_tapToScan": "Tap Scan to find MeshCore devices", + "scanner_connectionFailed": "Connection failed: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": {"type": "String"} + } + }, + "scanner_stop": "Stop", + "scanner_scan": "Scan", + + "device_quickSwitch": "Quick switch", + "device_meshcore": "MeshCore", + + "settings_title": "Settings", + "settings_deviceInfo": "Device Info", + "settings_appSettings": "App Settings", + "settings_appSettingsSubtitle": "Notifications, messaging, and map preferences", + "settings_nodeSettings": "Node Settings", + "settings_nodeName": "Node Name", + "settings_nodeNameNotSet": "Not set", + "settings_nodeNameHint": "Enter node name", + "settings_nodeNameUpdated": "Name updated", + "settings_radioSettings": "Radio Settings", + "settings_radioSettingsSubtitle": "Frequency, power, spreading factor", + "settings_radioSettingsUpdated": "Radio settings updated", + "settings_location": "Location", + "settings_locationSubtitle": "GPS coordinates", + "settings_locationUpdated": "Location updated", + "settings_locationBothRequired": "Enter both latitude and longitude.", + "settings_locationInvalid": "Invalid latitude or longitude.", + "settings_latitude": "Latitude", + "settings_longitude": "Longitude", + "settings_privacyMode": "Privacy Mode", + "settings_privacyModeSubtitle": "Hide name/location in advertisements", + "settings_privacyModeToggle": "Toggle privacy mode to hide your name and location in advertisements.", + "settings_privacyModeEnabled": "Privacy mode enabled", + "settings_privacyModeDisabled": "Privacy mode disabled", + "settings_actions": "Actions", + "settings_sendAdvertisement": "Send Advertisement", + "settings_sendAdvertisementSubtitle": "Broadcast presence now", + "settings_advertisementSent": "Advertisement sent", + "settings_syncTime": "Sync Time", + "settings_syncTimeSubtitle": "Set device clock to phone time", + "settings_timeSynchronized": "Time synchronized", + "settings_refreshContacts": "Refresh Contacts", + "settings_refreshContactsSubtitle": "Reload contact list from device", + "settings_rebootDevice": "Reboot Device", + "settings_rebootDeviceSubtitle": "Restart the MeshCore device", + "settings_rebootDeviceConfirm": "Are you sure you want to reboot the device? You will be disconnected.", + "settings_debug": "Debug", + "settings_bleDebugLog": "BLE Debug Log", + "settings_bleDebugLogSubtitle": "BLE commands, responses, and raw data", + "settings_appDebugLog": "App Debug Log", + "settings_appDebugLogSubtitle": "Application debug messages", + "settings_about": "About", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": {"type": "String"} + } + }, + "settings_aboutLegalese": "2026 MeshCore Open Source Project", + "settings_aboutDescription": "An open-source Flutter client for MeshCore LoRa mesh networking devices.", + "settings_infoName": "Name", + "settings_infoId": "ID", + "settings_infoStatus": "Status", + "settings_infoBattery": "Battery", + "settings_infoPublicKey": "Public Key", + "settings_infoContactsCount": "Contacts Count", + "settings_infoChannelCount": "Channel Count", + "settings_presets": "Presets", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Frequency (MHz)", + "settings_frequencyHelper": "300.0 - 2500.0", + "settings_frequencyInvalid": "Invalid frequency (300-2500 MHz)", + "settings_bandwidth": "Bandwidth", + "settings_spreadingFactor": "Spreading Factor", + "settings_codingRate": "Coding Rate", + "settings_txPower": "TX Power (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Invalid TX power (0-22 dBm)", + "settings_longRange": "Long Range", + "settings_fastSpeed": "Fast Speed", + "settings_error": "Error: {message}", + "@settings_error": { + "placeholders": { + "message": {"type": "String"} + } + }, + + "appSettings_title": "App Settings", + "appSettings_appearance": "Appearance", + "appSettings_theme": "Theme", + "appSettings_themeSystem": "System default", + "appSettings_themeLight": "Light", + "appSettings_themeDark": "Dark", + "appSettings_language": "Language", + "appSettings_languageSystem": "System default", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Notifications", + "appSettings_enableNotifications": "Enable Notifications", + "appSettings_enableNotificationsSubtitle": "Receive notifications for messages and adverts", + "appSettings_notificationPermissionDenied": "Notification permission denied", + "appSettings_notificationsEnabled": "Notifications enabled", + "appSettings_notificationsDisabled": "Notifications disabled", + "appSettings_messageNotifications": "Message Notifications", + "appSettings_messageNotificationsSubtitle": "Show notification when receiving new messages", + "appSettings_channelMessageNotifications": "Channel Message Notifications", + "appSettings_channelMessageNotificationsSubtitle": "Show notification when receiving channel messages", + "appSettings_advertisementNotifications": "Advertisement Notifications", + "appSettings_advertisementNotificationsSubtitle": "Show notification when new nodes are discovered", + "appSettings_messaging": "Messaging", + "appSettings_clearPathOnMaxRetry": "Clear Path on Max Retry", + "appSettings_clearPathOnMaxRetrySubtitle": "Reset contact path after 5 failed send attempts", + "appSettings_pathsWillBeCleared": "Paths will be cleared after 5 failed retries", + "appSettings_pathsWillNotBeCleared": "Paths will not be auto-cleared", + "appSettings_autoRouteRotation": "Auto Route Rotation", + "appSettings_autoRouteRotationSubtitle": "Cycle between best paths and flood mode", + "appSettings_autoRouteRotationEnabled": "Auto route rotation enabled", + "appSettings_autoRouteRotationDisabled": "Auto route rotation disabled", + "appSettings_battery": "Battery", + "appSettings_batteryChemistry": "Battery Chemistry", + "appSettings_batteryChemistryPerDevice": "Set per device ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": {"type": "String"} + } + }, + "appSettings_batteryChemistryConnectFirst": "Connect to a device to choose", + "appSettings_batteryNmc": "18650 NMC (3.0-4.2V)", + "appSettings_batteryLifepo4": "LiFePO4 (2.6-3.65V)", + "appSettings_batteryLipo": "LiPo (3.0-4.2V)", + "appSettings_mapDisplay": "Map Display", + "appSettings_showRepeaters": "Show Repeaters", + "appSettings_showRepeatersSubtitle": "Display repeater nodes on the map", + "appSettings_showChatNodes": "Show Chat Nodes", + "appSettings_showChatNodesSubtitle": "Display chat nodes on the map", + "appSettings_showOtherNodes": "Show Other Nodes", + "appSettings_showOtherNodesSubtitle": "Display other node types on the map", + "appSettings_timeFilter": "Time Filter", + "appSettings_timeFilterShowAll": "Show all nodes", + "appSettings_timeFilterShowLast": "Show nodes from last {hours} hours", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": {"type": "int"} + } + }, + "appSettings_mapTimeFilter": "Map Time Filter", + "appSettings_showNodesDiscoveredWithin": "Show nodes discovered within:", + "appSettings_allTime": "All time", + "appSettings_lastHour": "Last hour", + "appSettings_last6Hours": "Last 6 hours", + "appSettings_last24Hours": "Last 24 hours", + "appSettings_lastWeek": "Last week", + "appSettings_offlineMapCache": "Offline Map Cache", + "appSettings_noAreaSelected": "No area selected", + "appSettings_areaSelectedZoom": "Area selected (zoom {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": {"type": "int"}, + "maxZoom": {"type": "int"} + } + }, + "appSettings_debugCard": "Debug", + "appSettings_appDebugLogging": "App Debug Logging", + "appSettings_appDebugLoggingSubtitle": "Log app debug messages for troubleshooting", + "appSettings_appDebugLoggingEnabled": "App debug logging enabled", + "appSettings_appDebugLoggingDisabled": "App debug logging disabled", + + "contacts_title": "Contacts", + "contacts_noContacts": "No contacts yet", + "contacts_contactsWillAppear": "Contacts will appear when devices advertise", + "contacts_searchContacts": "Search contacts...", + "contacts_noUnreadContacts": "No unread contacts", + "contacts_noContactsFound": "No contacts or groups found", + "contacts_deleteContact": "Delete Contact", + "contacts_removeConfirm": "Remove {contactName} from contacts?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": {"type": "String"} + } + }, + "contacts_manageRepeater": "Manage Repeater", + "contacts_roomLogin": "Room Login", + "contacts_openChat": "Open Chat", + "contacts_editGroup": "Edit Group", + "contacts_deleteGroup": "Delete Group", + "contacts_deleteGroupConfirm": "Remove \"{groupName}\"?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": {"type": "String"} + } + }, + "contacts_newGroup": "New Group", + "contacts_groupName": "Group name", + "contacts_groupNameRequired": "Group name is required", + "contacts_groupAlreadyExists": "Group \"{name}\" already exists", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": {"type": "String"} + } + }, + "contacts_filterContacts": "Filter contacts...", + "contacts_noContactsMatchFilter": "No contacts match your filter", + "contacts_noMembers": "No members", + "contacts_lastSeenNow": "Last seen now", + "contacts_lastSeenMinsAgo": "Last seen {minutes} mins ago", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": {"type": "int"} + } + }, + "contacts_lastSeenHourAgo": "Last seen 1 hour ago", + "contacts_lastSeenHoursAgo": "Last seen {hours} hours ago", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": {"type": "int"} + } + }, + "contacts_lastSeenDayAgo": "Last seen 1 day ago", + "contacts_lastSeenDaysAgo": "Last seen {days} days ago", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": {"type": "int"} + } + }, + + "channels_title": "Channels", + "channels_noChannelsConfigured": "No channels configured", + "channels_addPublicChannel": "Add Public Channel", + "channels_searchChannels": "Search channels...", + "channels_noChannelsFound": "No channels found", + "channels_channelIndex": "Channel {index}", + "@channels_channelIndex": { + "placeholders": { + "index": {"type": "int"} + } + }, + "channels_hashtagChannel": "Hashtag channel", + "channels_public": "Public", + "channels_private": "Private", + "channels_publicChannel": "Public channel", + "channels_privateChannel": "Private channel", + "channels_editChannel": "Edit channel", + "channels_deleteChannel": "Delete channel", + "channels_deleteChannelConfirm": "Delete \"{name}\"? This cannot be undone.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": {"type": "String"} + } + }, + "channels_channelDeleted": "Channel \"{name}\" deleted", + "@channels_channelDeleted": { + "placeholders": { + "name": {"type": "String"} + } + }, + "channels_addChannel": "Add Channel", + "channels_channelIndexLabel": "Channel Index", + "channels_channelName": "Channel Name", + "channels_usePublicChannel": "Use Public Channel", + "channels_standardPublicPsk": "Standard public PSK", + "channels_pskHex": "PSK (Hex)", + "channels_generateRandomPsk": "Generate random PSK", + "channels_enterChannelName": "Please enter a channel name", + "channels_pskMustBe32Hex": "PSK must be 32 hex characters", + "channels_channelAdded": "Channel \"{name}\" added", + "@channels_channelAdded": { + "placeholders": { + "name": {"type": "String"} + } + }, + "channels_editChannelTitle": "Edit Channel {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": {"type": "int"} + } + }, + "channels_smazCompression": "SMAZ compression", + "channels_channelUpdated": "Channel \"{name}\" updated", + "@channels_channelUpdated": { + "placeholders": { + "name": {"type": "String"} + } + }, + "channels_publicChannelAdded": "Public channel added", + "channels_sortBy": "Sort by", + "channels_sortManual": "Manual", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "Latest messages", + "channels_sortUnread": "Unread", + + "chat_noMessages": "No messages yet", + "chat_sendMessageToStart": "Send a message to get started", + "chat_originalMessageNotFound": "Original message not found", + "chat_replyingTo": "Replying to {name}", + "@chat_replyingTo": { + "placeholders": { + "name": {"type": "String"} + } + }, + "chat_replyTo": "Reply to {name}", + "@chat_replyTo": { + "placeholders": { + "name": {"type": "String"} + } + }, + "chat_location": "Location", + "chat_sendMessageTo": "Send a message to {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": {"type": "String"} + } + }, + "chat_typeMessage": "Type a message...", + "chat_messageTooLong": "Message too long (max {maxBytes} bytes).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": {"type": "int"} + } + }, + "chat_messageCopied": "Message copied", + "chat_messageDeleted": "Message deleted", + "chat_retryingMessage": "Retrying message", + "chat_retryCount": "Retry {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": {"type": "int"}, + "max": {"type": "int"} + } + }, + "chat_sendGif": "Send GIF", + "chat_reply": "Reply", + "chat_addReaction": "Add Reaction", + "chat_me": "Me", + "emojiCategorySmileys": "Smileys", + "emojiCategoryGestures": "Gestures", + "emojiCategoryHearts": "Hearts", + "emojiCategoryObjects": "Objects", + "gifPicker_title": "Choose a GIF", + "gifPicker_searchHint": "Search GIFs...", + "gifPicker_poweredBy": "Powered by GIPHY", + "gifPicker_noGifsFound": "No GIFs found", + "gifPicker_failedLoad": "Failed to load GIFs", + "gifPicker_failedSearch": "Failed to search GIFs", + "gifPicker_noInternet": "No internet connection", + "debugLog_appTitle": "App Debug Log", + "debugLog_bleTitle": "BLE Debug Log", + "debugLog_copyLog": "Copy log", + "debugLog_clearLog": "Clear log", + "debugLog_copied": "Debug log copied", + "debugLog_bleCopied": "BLE log copied", + "debugLog_noEntries": "No debug logs yet", + "debugLog_enableInSettings": "Enable app debug logging in settings", + "debugLog_frames": "Frames", + "debugLog_rawLogRx": "Raw Log-RX", + "debugLog_noBleActivity": "No BLE activity yet", + "debugFrame_length": "Frame Length: {count} bytes", + "@debugFrame_length": { + "placeholders": { + "count": {"type": "int"} + } + }, + "debugFrame_command": "Command: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": {"type": "String"} + } + }, + "debugFrame_textMessageHeader": "Text Message Frame:", + "debugFrame_destinationPubKey": "- Destination PubKey: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": {"type": "String"} + } + }, + "debugFrame_timestamp": "- Timestamp: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": {"type": "int"} + } + }, + "debugFrame_flags": "- Flags: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": {"type": "String"} + } + }, + "debugFrame_textType": "- Text Type: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": {"type": "int"}, + "label": {"type": "String"} + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Plain", + "debugFrame_text": "- Text: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": {"type": "String"} + } + }, + "debugFrame_hexDump": "Hex Dump:", + "chat_pathManagement": "Path Management", + "chat_routingMode": "Routing mode", + "chat_autoUseSavedPath": "Auto (use saved path)", + "chat_forceFloodMode": "Force Flood Mode", + "chat_recentAckPaths": "Recent ACK Paths (tap to use):", + "chat_pathHistoryFull": "Path history is full. Remove entries to add new ones.", + "chat_hopSingular": "hop", + "chat_hopPlural": "hops", + "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": {"type": "int"} + } + }, + "chat_successes": "successes", + "chat_removePath": "Remove path", + "chat_noPathHistoryYet": "No path history yet.\nSend a message to discover paths.", + "chat_pathActions": "Path Actions:", + "chat_setCustomPath": "Set Custom Path", + "chat_setCustomPathSubtitle": "Manually specify routing path", + "chat_clearPath": "Clear Path", + "chat_clearPathSubtitle": "Force rediscovery on next send", + "chat_pathCleared": "Path cleared. Next message will rediscover route.", + "chat_floodModeSubtitle": "Use routing toggle in app bar", + "chat_floodModeEnabled": "Flood mode enabled. Toggle back via routing icon in app bar.", + "chat_fullPath": "Full Path", + "chat_pathDetailsNotAvailable": "Path details not available yet. Try sending a message to refresh.", + "chat_pathSetHops": "Path set: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": {"type": "int"}, + "status": {"type": "String"} + } + }, + "chat_pathSavedLocally": "Saved locally. Connect to sync.", + "chat_pathDeviceConfirmed": "Device confirmed.", + "chat_pathDeviceNotConfirmed": "Device not confirmed yet.", + "chat_type": "Type", + "chat_path": "Path", + "chat_publicKey": "Public Key", + "chat_compressOutgoingMessages": "Compress outgoing messages", + "chat_floodForced": "Flood (forced)", + "chat_directForced": "Direct (forced)", + "chat_hopsForced": "{count} hops (forced)", + "@chat_hopsForced": { + "placeholders": { + "count": {"type": "int"} + } + }, + "chat_floodAuto": "Flood (auto)", + "chat_direct": "Direct", + "chat_poiShared": "POI Shared", + "chat_unread": "Unread: {count}", + "@chat_unread": { + "placeholders": { + "count": {"type": "int"} + } + }, + + "map_title": "Node Map", + "map_noNodesWithLocation": "No nodes with location data", + "map_nodesNeedGps": "Nodes need to share their GPS coordinates\nto appear on the map", + "map_nodesCount": "Nodes: {count}", + "@map_nodesCount": { + "placeholders": { + "count": {"type": "int"} + } + }, + "map_pinsCount": "Pins: {count}", + "@map_pinsCount": { + "placeholders": { + "count": {"type": "int"} + } + }, + "map_chat": "Chat", + "map_repeater": "Repeater", + "map_room": "Room", + "map_sensor": "Sensor", + "map_pinDm": "Pin (DM)", + "map_pinPrivate": "Pin (Private)", + "map_pinPublic": "Pin (Public)", + "map_lastSeen": "Last Seen", + "map_disconnectConfirm": "Are you sure you want to disconnect from this device?", + "map_from": "From", + "map_source": "Source", + "map_flags": "Flags", + "map_shareMarkerHere": "Share marker here", + "map_pinLabel": "Pin label", + "map_label": "Label", + "map_pointOfInterest": "Point of interest", + "map_sendToContact": "Send to contact", + "map_sendToChannel": "Send to channel", + "map_noChannelsAvailable": "No channels available", + "map_publicLocationShare": "Public location share", + "map_publicLocationShareConfirm": "You are about to share a location in {channelLabel}. This channel is public and anyone with the PSK can see it.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": {"type": "String"} + } + }, + "map_connectToShareMarkers": "Connect to a device to share markers", + "map_filterNodes": "Filter Nodes", + "map_nodeTypes": "Node Types", + "map_chatNodes": "Chat Nodes", + "map_repeaters": "Repeaters", + "map_otherNodes": "Other Nodes", + "map_keyPrefix": "Key Prefix", + "map_filterByKeyPrefix": "Filter by key prefix", + "map_publicKeyPrefix": "Public key prefix", + "map_markers": "Markers", + "map_showSharedMarkers": "Show shared markers", + "map_lastSeenTime": "Last Seen Time", + "map_sharedPin": "Shared pin", + "map_joinRoom": "Join Room", + "map_manageRepeater": "Manage Repeater", + "mapCache_title": "Offline Map Cache", + "mapCache_selectAreaFirst": "Select an area to cache first", + "mapCache_noTilesToDownload": "No tiles to download for this area", + "mapCache_downloadTilesTitle": "Download tiles", + "mapCache_downloadTilesPrompt": "Download {count} tiles for offline use?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": {"type": "int"} + } + }, + "mapCache_downloadAction": "Download", + "mapCache_cachedTiles": "Cached {count} tiles", + "@mapCache_cachedTiles": { + "placeholders": { + "count": {"type": "int"} + } + }, + "mapCache_cachedTilesWithFailed": "Cached {downloaded} tiles ({failed} failed)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": {"type": "int"}, + "failed": {"type": "int"} + } + }, + "mapCache_clearOfflineCacheTitle": "Clear offline cache", + "mapCache_clearOfflineCachePrompt": "Remove all cached map tiles?", + "mapCache_offlineCacheCleared": "Offline cache cleared", + "mapCache_noAreaSelected": "No area selected", + "mapCache_cacheArea": "Cache Area", + "mapCache_useCurrentView": "Use Current View", + "mapCache_zoomRange": "Zoom Range", + "mapCache_estimatedTiles": "Estimated tiles: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": {"type": "int"} + } + }, + "mapCache_downloadedTiles": "Downloaded {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": {"type": "int"}, + "total": {"type": "int"} + } + }, + "mapCache_downloadTilesButton": "Download Tiles", + "mapCache_clearCacheButton": "Clear Cache", + "mapCache_failedDownloads": "Failed downloads: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": {"type": "int"} + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": {"type": "String"}, + "south": {"type": "String"}, + "east": {"type": "String"}, + "west": {"type": "String"} + } + }, + + "time_justNow": "Just now", + "time_minutesAgo": "{minutes}m ago", + "@time_minutesAgo": { + "placeholders": { + "minutes": {"type": "int"} + } + }, + "time_hoursAgo": "{hours}h ago", + "@time_hoursAgo": { + "placeholders": { + "hours": {"type": "int"} + } + }, + "time_daysAgo": "{days}d ago", + "@time_daysAgo": { + "placeholders": { + "days": {"type": "int"} + } + }, + "time_hour": "hour", + "time_hours": "hours", + "time_day": "day", + "time_days": "days", + "time_week": "week", + "time_weeks": "weeks", + "time_month": "month", + "time_months": "months", + "time_minutes": "minutes", + "time_allTime": "All Time", + + "dialog_disconnect": "Disconnect", + "dialog_disconnectConfirm": "Are you sure you want to disconnect from this device?", + + "login_repeaterLogin": "Repeater Login", + "login_roomLogin": "Room Login", + "login_password": "Password", + "login_enterPassword": "Enter password", + "login_savePassword": "Save password", + "login_savePasswordSubtitle": "Password will be stored securely on this device", + "login_repeaterDescription": "Enter the repeater password to access settings and status.", + "login_roomDescription": "Enter the room password to access settings and status.", + "login_routing": "Routing", + "login_routingMode": "Routing mode", + "login_autoUseSavedPath": "Auto (use saved path)", + "login_forceFloodMode": "Force Flood Mode", + "login_managePaths": "Manage Paths", + "login_login": "Login", + "login_attempt": "Attempt {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": {"type": "int"}, + "max": {"type": "int"} + } + }, + "login_failed": "Login failed: {error}", + "@login_failed": { + "placeholders": { + "error": {"type": "String"} + } + }, + + "common_reload": "Reload", + "common_clear": "Clear", + + "path_currentPath": "Current path: {path}", + "@path_currentPath": { + "placeholders": { + "path": {"type": "String"} + } + }, + "path_usingHopsPath": "Using {count} {count, plural, =1{hop} other{hops}} path", + "@path_usingHopsPath": { + "placeholders": { + "count": {"type": "int"} + } + }, + "path_enterCustomPath": "Enter Custom Path", + "path_currentPathLabel": "Current path", + "path_hexPrefixInstructions": "Enter 2-character hex prefixes for each hop, separated by commas.", + "path_hexPrefixExample": "Example: A1,F2,3C (each node uses first byte of its public key)", + "path_labelHexPrefixes": "Path (hex prefixes)", + "path_helperMaxHops": "Max 64 hops. Each prefix is 2 hex characters (1 byte)", + "path_selectFromContacts": "Or select from contacts:", + "path_noRepeatersFound": "No repeaters or room servers found.", + "path_customPathsRequire": "Custom paths require intermediate hops that can relay messages.", + "path_invalidHexPrefixes": "Invalid hex prefixes: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": {"type": "String"} + } + }, + "path_tooLong": "Path too long. Maximum 64 hops allowed.", + "path_setPath": "Set Path", + + "repeater_management": "Repeater Management", + "repeater_managementTools": "Management Tools", + "repeater_status": "Status", + "repeater_statusSubtitle": "View repeater status, stats, and neighbors", + "repeater_telemetry": "Telemetry", + "repeater_telemetrySubtitle": "View telemetry of sensors and system stats", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Send commands to the repeater", + "repeater_settings": "Settings", + "repeater_settingsSubtitle": "Configure repeater parameters", + + "repeater_statusTitle": "Repeater Status", + "repeater_routingMode": "Routing mode", + "repeater_autoUseSavedPath": "Auto (use saved path)", + "repeater_forceFloodMode": "Force Flood Mode", + "repeater_pathManagement": "Path management", + "repeater_refresh": "Refresh", + "repeater_statusRequestTimeout": "Status request timed out.", + "repeater_errorLoadingStatus": "Error loading status: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": {"type": "String"} + } + }, + "repeater_systemInformation": "System Information", + "repeater_battery": "Battery", + "repeater_clockAtLogin": "Clock (at login)", + "repeater_uptime": "Uptime", + "repeater_queueLength": "Queue Length", + "repeater_debugFlags": "Debug Flags", + "repeater_radioStatistics": "Radio Statistics", + "repeater_lastRssi": "Last RSSI", + "repeater_lastSnr": "Last SNR", + "repeater_noiseFloor": "Noise Floor", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Packet Statistics", + "repeater_sent": "Sent", + "repeater_received": "Received", + "repeater_duplicates": "Duplicates", + "repeater_daysHoursMinsSecs": "{days} days {hours}h {minutes}m {seconds}s", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": {"type": "int"}, + "hours": {"type": "int"}, + "minutes": {"type": "int"}, + "seconds": {"type": "int"} + } + }, + "repeater_packetTxTotal": "Total: {total}, Flood: {flood}, Direct: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": {"type": "int"}, + "flood": {"type": "String"}, + "direct": {"type": "String"} + } + }, + "repeater_packetRxTotal": "Total: {total}, Flood: {flood}, Direct: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": {"type": "int"}, + "flood": {"type": "String"}, + "direct": {"type": "String"} + } + }, + "repeater_duplicatesFloodDirect": "Flood: {flood}, Direct: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": {"type": "String"}, + "direct": {"type": "String"} + } + }, + "repeater_duplicatesTotal": "Total: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": {"type": "int"} + } + }, + + "repeater_settingsTitle": "Repeater Settings", + "repeater_basicSettings": "Basic Settings", + "repeater_repeaterName": "Repeater Name", + "repeater_repeaterNameHelper": "Display name for this repeater", + "repeater_adminPassword": "Admin Password", + "repeater_adminPasswordHelper": "Full access password", + "repeater_guestPassword": "Guest Password", + "repeater_guestPasswordHelper": "Read-only access password", + "repeater_radioSettings": "Radio Settings", + "repeater_frequencyMhz": "Frequency (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Power", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Bandwidth", + "repeater_spreadingFactor": "Spreading Factor", + "repeater_codingRate": "Coding Rate", + "repeater_locationSettings": "Location Settings", + "repeater_latitude": "Latitude", + "repeater_latitudeHelper": "Decimal degrees (e.g., 37.7749)", + "repeater_longitude": "Longitude", + "repeater_longitudeHelper": "Decimal degrees (e.g., -122.4194)", + "repeater_features": "Features", + "repeater_packetForwarding": "Packet Forwarding", + "repeater_packetForwardingSubtitle": "Enable repeater to forward packets", + "repeater_guestAccess": "Guest Access", + "repeater_guestAccessSubtitle": "Allow read-only guest access", + "repeater_privacyMode": "Privacy Mode", + "repeater_privacyModeSubtitle": "Hide name/location in advertisements", + "repeater_advertisementSettings": "Advertisement Settings", + "repeater_localAdvertInterval": "Local Advertisement Interval", + "repeater_localAdvertIntervalMinutes": "{minutes} minutes", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": {"type": "int"} + } + }, + "repeater_floodAdvertInterval": "Flood Advertisement Interval", + "repeater_floodAdvertIntervalHours": "{hours} hours", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": {"type": "int"} + } + }, + "repeater_encryptedAdvertInterval": "Encrypted Advertisement Interval", + "repeater_dangerZone": "Danger Zone", + "repeater_rebootRepeater": "Reboot Repeater", + "repeater_rebootRepeaterSubtitle": "Restart the repeater device", + "repeater_rebootRepeaterConfirm": "Are you sure you want to reboot this repeater?", + "repeater_regenerateIdentityKey": "Regenerate Identity Key", + "repeater_regenerateIdentityKeySubtitle": "Generate new public/private key pair", + "repeater_regenerateIdentityKeyConfirm": "This will generate a new identity for the repeater. Continue?", + "repeater_eraseFileSystem": "Erase File System", + "repeater_eraseFileSystemSubtitle": "Format the repeater file system", + "repeater_eraseFileSystemConfirm": "WARNING: This will erase all data on the repeater. This cannot be undone!", + "repeater_eraseSerialOnly": "Erase is only available over serial console.", + "repeater_commandSent": "Command sent: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": {"type": "String"} + } + }, + "repeater_errorSendingCommand": "Error sending command: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": {"type": "String"} + } + }, + "repeater_confirm": "Confirm", + "repeater_settingsSaved": "Settings saved successfully", + "repeater_errorSavingSettings": "Error saving settings: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": {"type": "String"} + } + }, + "repeater_refreshBasicSettings": "Refresh Basic Settings", + "repeater_refreshRadioSettings": "Refresh Radio Settings", + "repeater_refreshTxPower": "Refresh TX power", + "repeater_refreshLocationSettings": "Refresh Location Settings", + "repeater_refreshPacketForwarding": "Refresh Packet Forwarding", + "repeater_refreshGuestAccess": "Refresh Guest Access", + "repeater_refreshPrivacyMode": "Refresh Privacy Mode", + "repeater_refreshAdvertisementSettings": "Refresh Advertisement Settings", + "repeater_refreshed": "{label} refreshed", + "@repeater_refreshed": { + "placeholders": { + "label": {"type": "String"} + } + }, + "repeater_errorRefreshing": "Error refreshing {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": {"type": "String"} + } + }, + + "repeater_cliTitle": "Repeater CLI", + "repeater_debugNextCommand": "Debug Next Command", + "repeater_commandHelp": "Command Help", + "repeater_clearHistory": "Clear History", + "repeater_noCommandsSent": "No commands sent yet", + "repeater_typeCommandOrUseQuick": "Type a command below or use quick commands", + "repeater_enterCommandHint": "Enter command...", + "repeater_previousCommand": "Previous command", + "repeater_nextCommand": "Next command", + "repeater_enterCommandFirst": "Enter a command first", + "repeater_cliCommandFrameTitle": "CLI Command Frame", + "repeater_cliCommandError": "Error: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": {"type": "String"} + } + }, + "repeater_cliQuickGetName": "Get Name", + "repeater_cliQuickGetRadio": "Get Radio", + "repeater_cliQuickGetTx": "Get TX", + "repeater_cliQuickNeighbors": "Neighbors", + "repeater_cliQuickVersion": "Version", + "repeater_cliQuickAdvertise": "Advertise", + "repeater_cliQuickClock": "Clock", + "repeater_cliHelpAdvert": "Sends an advertisement packet", + "repeater_cliHelpReboot": "Reboots the device. (note, you'll prob get 'Timeout' which is normal)", + "repeater_cliHelpClock": "Displays current time per device's clock.", + "repeater_cliHelpPassword": "Sets a new admin password for the device.", + "repeater_cliHelpVersion": "Shows the device version and firmware build date.", + "repeater_cliHelpClearStats": "Resets various stats counters to zero.", + "repeater_cliHelpSetAf": "Sets the air-time-factor.", + "repeater_cliHelpSetTx": "Sets LoRa transmit power in dBm. (reboot to apply)", + "repeater_cliHelpSetRepeat": "Enables or disables the repeater role for this node.", + "repeater_cliHelpSetAllowReadOnly": "(Room server) If 'on', then login in blank password will be allowed, but cannot Post to room. (just read only)", + "repeater_cliHelpSetFloodMax": "Sets the maximum number of hops of inbound flood packet (if >= max, packet is not forwarded)", + "repeater_cliHelpSetIntThresh": "Sets the Interference Threshold (in DB). Default is 14. Set to 0 to disable channel interference detection.", + "repeater_cliHelpSetAgcResetInterval": "Sets the interval to reset the Auto Gain Controller. Set to 0 to disable.", + "repeater_cliHelpSetMultiAcks": "Enables or disables the 'double ACKs' feature.", + "repeater_cliHelpSetAdvertInterval": "Sets the timer interval in minutes to send a local (zero-hop) advertisement packet. Set to 0 to disable.", + "repeater_cliHelpSetFloodAdvertInterval": "Sets the timer interval in hours to send a flood advertisement packet. Set to 0 to disable.", + "repeater_cliHelpSetGuestPassword": "Sets/updates the guest password. (for repeaters, guest logins can send the \"Get Stats\" request)", + "repeater_cliHelpSetName": "Sets the advertisement name.", + "repeater_cliHelpSetLat": "Sets the advertisement map latitude. (decimal degrees)", + "repeater_cliHelpSetLon": "Sets the advertisement map longitude. (decimal degrees)", + "repeater_cliHelpSetRadio": "Sets completely new radio params, and saves to preferences. Requires a \"reboot\" command to apply.", + "repeater_cliHelpSetRxDelay": "Sets (experimental) base (must be > 1 for effect) for applying slight delay to received packets, based on signal strength/score. Set to 0 to disable.", + "repeater_cliHelpSetTxDelay": "Sets a factor multiplied with time-on-air for a flood-mode packet and with a randomized slot system, to delay its forwarding. (to decrease likelihood of collisions)", + "repeater_cliHelpSetDirectTxDelay": "Same as txdelay, but for applying a random delay to the forwarding of direct-mode packets.", + "repeater_cliHelpSetBridgeEnabled": "Enable/Disable bridge.", + "repeater_cliHelpSetBridgeDelay": "Set delay before retransmitting packets.", + "repeater_cliHelpSetBridgeSource": "Choose wether the bridge will retransmit received packets or transmitted packets.", + "repeater_cliHelpSetBridgeBaud": "Set serial link baudrate for rs232 bridges.", + "repeater_cliHelpSetBridgeSecret": "Set bridge secret for espnow bridges.", + "repeater_cliHelpSetAdcMultiplier": "Sets custom factor to adjust reported battery voltage (only supported on select boards).", + "repeater_cliHelpTempRadio": "Sets temporary radio params for the given number of minutes, reverting to original radio params afterward. (does NOT save to preferences).", + "repeater_cliHelpSetPerm": "Modifies the ACL. Removes matching entry (by pubkey prefix) if \"permissions\" is zero. Adds new entry if pubkey-hex is full length and is not currently in ACL. Updates entry by matching pubkey prefix. Permission bits vary per firmware role, but low 2 bits are: 0 (Guest), 1 (Read only), 2 (Read write), 3 (Admin)", + "repeater_cliHelpGetBridgeType": "Gets bridge type none, rs232, espnow", + "repeater_cliHelpLogStart": "Starts packet logging to file system.", + "repeater_cliHelpLogStop": "Stops packet logging to file system.", + "repeater_cliHelpLogErase": "Erases the packet logs from file system.", + "repeater_cliHelpNeighbors": "Shows a list of other repeater nodes heard via zero-hop adverts. Each line is id-prefix-hex:timestamp:snr-times-4", + "repeater_cliHelpNeighborRemove": "Removes first matching entry (by pubkey prefix (hex)), from neighbors list.", + "repeater_cliHelpRegion": "(serial only) Lists all defined regions and current flood permissions.", + "repeater_cliHelpRegionLoad": "NOTE: this is a special multi-command invocation. Each subsequent command is a region name (indented with spaces to indicate parent hierarchy, with one space at minimum). Terminated by sending a blank line/command.", + "repeater_cliHelpRegionGet": "Searches for region with given name prefix (or \"*\" for the global scope). Replies with \"-> region-name (parent-name) 'F'\"", + "repeater_cliHelpRegionPut": "Adds or updates a region definition with given name.", + "repeater_cliHelpRegionRemove": "Removes a region definition with given name. (must match exactly, and have no child regions)", + "repeater_cliHelpRegionAllowf": "Sets the 'F'lood permission for the given region. ('*' for the global/legacy scope)", + "repeater_cliHelpRegionDenyf": "Removes the 'F'lood permission for the given region. (NOTE: at this stage NOT advised to use this on the global/legacy scope!!)", + "repeater_cliHelpRegionHome": "Replies with the current 'home' region. (Note applied anywhere yet, reserved for future)", + "repeater_cliHelpRegionHomeSet": "Sets the 'home' region.", + "repeater_cliHelpRegionSave": "Persists the region list/map to storage.", + "repeater_cliHelpGps": "Gives status of gps. When gps is off, it replies only off, if on it replies with on, status, fix, sat count", + "repeater_cliHelpGpsOnOff": "Toggles gps power state.", + "repeater_cliHelpGpsSync": "Syncs node time with gps clock.", + "repeater_cliHelpGpsSetLoc": "Sets node's position to gps coordinates and save preferences.", + "repeater_cliHelpGpsAdvert": "Gives location advert configuration of the node:\n- none: don't include location in adverts\n- share: share gps location (from SensorManager)\n- prefs: advert the location stored in preferences", + "repeater_cliHelpGpsAdvertSet": "Sets location advert configuration.", + "repeater_commandsListTitle": "Commands List", + "repeater_commandsListNote": "NOTE: for the various \"set ...\" commands, there is also a \"get ...\" command.", + "repeater_general": "General", + "repeater_settingsCategory": "Settings", + "repeater_bridge": "Bridge", + "repeater_logging": "Logging", + "repeater_neighborsRepeaterOnly": "Neighbors (Repeater only)", + "repeater_regionManagementRepeaterOnly": "Region Management (Repeater only)", + "repeater_regionNote": "Region commands have been introduced to manage region definitions and permissions.", + "repeater_gpsManagement": "GPS Management", + "repeater_gpsNote": "gps command has been introduced to manage location related topics.", + "telemetry_receivedData": "Received Telemetry Data", + "telemetry_requestTimeout": "Telemetry request timed out.", + "telemetry_errorLoading": "Error loading telemetry: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": {"type": "String"} + } + }, + "telemetry_noData": "No telemetry data available.", + "telemetry_channelTitle": "Channel {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": {"type": "int"} + } + }, + "telemetry_batteryLabel": "Battery", + "telemetry_voltageLabel": "Voltage", + "telemetry_mcuTemperatureLabel": "MCU Temperature", + "telemetry_temperatureLabel": "Temperature", + "telemetry_currentLabel": "Current", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": {"type": "int"}, + "volts": {"type": "String"} + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": {"type": "String"} + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": {"type": "String"} + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": {"type": "String"}, + "fahrenheit": {"type": "String"} + } + }, + "channelPath_title": "Packet Path", + "channelPath_viewMap": "View map", + "channelPath_otherObservedPaths": "Other Observed Paths", + "channelPath_repeaterHops": "Repeater Hops", + "channelPath_noHopDetails": "Hop details are not provided for this packet.", + "channelPath_messageDetails": "Message Details", + "channelPath_senderLabel": "Sender", + "channelPath_timeLabel": "Time", + "channelPath_repeatsLabel": "Repeats", + "channelPath_pathLabel": "Path", + "channelPath_observedLabel": "Observed", + "channelPath_observedPathTitle": "Observed path {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": {"type": "int"}, + "hops": {"type": "String"} + } + }, + "channelPath_noLocationData": "No location data", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": {"type": "int"}, + "month": {"type": "int"}, + "time": {"type": "String"} + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": {"type": "String"} + } + }, + "channelPath_unknownPath": "Unknown", + "channelPath_floodPath": "Flood", + "channelPath_directPath": "Direct", + "channelPath_observedZeroOf": "0 of {total} hops", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": {"type": "int"} + } + }, + "channelPath_observedSomeOf": "{observed} of {total} hops", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": {"type": "int"}, + "total": {"type": "int"} + } + }, + "channelPath_mapTitle": "Path Map", + "channelPath_noRepeaterLocations": "No repeater locations available for this path.", + "channelPath_primaryPath": "Path {index} (Primary)", + "@channelPath_primaryPath": { + "placeholders": { + "index": {"type": "int"} + } + }, + "channelPath_pathLabel": "Path {index}", + "@channelPath_pathLabel": { + "placeholders": { + "index": {"type": "int"} + } + }, + "channelPath_pathLabelTitle": "Path", + "channelPath_observedPathHeader": "Observed Path", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": {"type": "String"}, + "prefixes": {"type": "String"} + } + }, + "channelPath_noHopDetailsAvailable": "No hop details available for this packet.", + "channelPath_unknownRepeater": "Unknown Repeater", + "listFilter_tooltip": "Filter and sort", + "listFilter_sortBy": "Sort by", + "listFilter_latestMessages": "Latest messages", + "listFilter_heardRecently": "Heard recently", + "listFilter_az": "A-Z", + "listFilter_filters": "Filters", + "listFilter_all": "All", + "listFilter_users": "Users", + "listFilter_repeaters": "Repeaters", + "listFilter_roomServers": "Room servers", + "listFilter_unreadOnly": "Unread only", + "listFilter_newGroup": "New group" +} diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb new file mode 100644 index 0000000..1515eb6 --- /dev/null +++ b/lib/l10n/app_es.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "es", + "appTitle": "MeshCore Open", + "nav_contacts": "Contactos", + "nav_channels": "Canales", + "nav_map": "Mapa", + "common_cancel": "Cancelar", + "common_connect": "Conectar", + "common_unknownDevice": "Dispositivo Desconocido", + "common_save": "Guardar", + "common_delete": "Eliminar", + "common_close": "Cerrar", + "common_edit": "Editar", + "common_add": "Añadir", + "common_settings": "Configuración", + "common_disconnect": "Desconectar", + "common_connected": "Conectado", + "common_disconnected": "Desconectado", + "common_create": "Crear", + "common_continue": "Continuar", + "common_share": "Compartir", + "common_copy": "Copiar", + "common_retry": "Intentar", + "common_hide": "Ocultar", + "common_remove": "Eliminar", + "common_enable": "Activar", + "common_disable": "Desactivar", + "common_reboot": "Reiniciar", + "common_loading": "Cargando...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Escaneando dispositivos...", + "scanner_connecting": "Conectando...", + "scanner_disconnecting": "Desconectando...", + "scanner_notConnected": "No está conectado", + "scanner_connectedTo": "Conectado a {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Buscando dispositivos MeshCore...", + "scanner_tapToScan": "Toca Escanear para encontrar dispositivos MeshCore", + "scanner_connectionFailed": "Error de conexión: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Detener", + "scanner_scan": "Escanea", + "device_quickSwitch": "Cambiar rápidamente", + "device_meshcore": "MeshCore", + "settings_title": "Configuración", + "settings_deviceInfo": "Información del dispositivo", + "settings_appSettings": "Configuración de la App", + "settings_appSettingsSubtitle": "Notificaciones, mensajes y preferencias de mapa", + "settings_nodeSettings": "Configuración del Nodo", + "settings_nodeName": "Nombre del nodo", + "settings_nodeNameNotSet": "No está configurado", + "settings_nodeNameHint": "Introducir nombre de nodo", + "settings_nodeNameUpdated": "Nombre actualizado", + "settings_radioSettings": "Configuración de Radio", + "settings_radioSettingsSubtitle": "Frecuencia, potencia, factor de dispersión", + "settings_radioSettingsUpdated": "Ajustes de radio actualizados", + "settings_location": "Ubicación", + "settings_locationSubtitle": "Coordenadas GPS", + "settings_locationUpdated": "Ubicación actualizada", + "settings_locationBothRequired": "Introduzca tanto la latitud como la longitud.", + "settings_locationInvalid": "Latitud o longitud inválidos.", + "settings_latitude": "Latitud", + "settings_longitude": "Longitud", + "settings_privacyMode": "Modo Privacidad", + "settings_privacyModeSubtitle": "Ocultar nombre/ubicación en anuncios", + "settings_privacyModeToggle": "Activar el modo de privacidad para ocultar tu nombre y ubicación en los anuncios.", + "settings_privacyModeEnabled": "Modo de privacidad activado", + "settings_privacyModeDisabled": "Modo de privacidad desactivado", + "settings_actions": "Acciones", + "settings_sendAdvertisement": "Enviar Anuncio", + "settings_sendAdvertisementSubtitle": "Presencia de transmisión ahora", + "settings_advertisementSent": "Anuncio enviado", + "settings_syncTime": "Tiempo de Sincronización", + "settings_syncTimeSubtitle": "Establecer la hora del dispositivo al tiempo del teléfono", + "settings_timeSynchronized": "Sincronizado en el tiempo", + "settings_refreshContacts": "Actualizar Contactos", + "settings_refreshContactsSubtitle": "Recargar lista de contactos del dispositivo", + "settings_rebootDevice": "Reiniciar Dispositivo", + "settings_rebootDeviceSubtitle": "Reiniciar el dispositivo MeshCore", + "settings_rebootDeviceConfirm": "¿Está seguro de que desea reiniciar el dispositivo? Se desconectará.", + "settings_debug": "Depurar", + "settings_bleDebugLog": "Registro de Depuración BLE", + "settings_bleDebugLogSubtitle": "Comandos, respuestas y datos brutos de BLE", + "settings_appDebugLog": "Registro de Depuración de la App", + "settings_appDebugLogSubtitle": "Mensajes de depuración de la aplicación", + "settings_about": "Acerca de", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "2026 Proyecto Open Source MeshCore", + "settings_aboutDescription": "Un cliente de código abierto de Flutter para dispositivos de red mesh LoRa de MeshCore.", + "settings_infoName": "Nombre", + "settings_infoId": "ID", + "settings_infoStatus": "Estado", + "settings_infoBattery": "Batería", + "settings_infoPublicKey": "Clave Pública", + "settings_infoContactsCount": "Número de contactos", + "settings_infoChannelCount": "Número de canales", + "settings_presets": "Preajustes", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Frecuencia (MHz)", + "settings_frequencyHelper": "300,0 - 2500,0", + "settings_frequencyInvalid": "Frecuencia inválida (300-2500 MHz)", + "settings_bandwidth": "Ancho de banda", + "settings_spreadingFactor": "Factor de propagación", + "settings_codingRate": "Tasa de Programación", + "settings_txPower": "TX Potencia (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Potencia de TX inválida (0-22 dBm)", + "settings_longRange": "Largo Alcance", + "settings_fastSpeed": "Velocidad Rápida", + "settings_error": "Error: {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "Configuración de la App", + "appSettings_appearance": "Apariencia", + "appSettings_theme": "Tema", + "appSettings_themeSystem": "Valor predeterminado del sistema", + "appSettings_themeLight": "Luz", + "appSettings_themeDark": "Oscuro", + "appSettings_language": "Idioma", + "appSettings_languageSystem": "Predeterminado del sistema", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Notificaciones", + "appSettings_enableNotifications": "Habilitar Notificaciones", + "appSettings_enableNotificationsSubtitle": "Recibir notificaciones para mensajes y anuncios", + "appSettings_notificationPermissionDenied": "Permiso de notificación denegado", + "appSettings_notificationsEnabled": "Notificaciones activadas", + "appSettings_notificationsDisabled": "Notificaciones desactivadas", + "appSettings_messageNotifications": "Notificaciones de Mensaje", + "appSettings_messageNotificationsSubtitle": "Mostrar notificación al recibir nuevos mensajes", + "appSettings_channelMessageNotifications": "Notificaciones de Mensajes del Canal", + "appSettings_channelMessageNotificationsSubtitle": "Mostrar notificación al recibir mensajes del canal", + "appSettings_advertisementNotifications": "Notificaciones de Anuncios", + "appSettings_advertisementNotificationsSubtitle": "Mostrar notificación cuando se descubren nuevos nodos", + "appSettings_messaging": "Mensajería", + "appSettings_clearPathOnMaxRetry": "Borrar Camino en Max Reintentos", + "appSettings_clearPathOnMaxRetrySubtitle": "Restablecer la ruta de contacto después de 5 intentos de envío fallidos", + "appSettings_pathsWillBeCleared": "Los caminos se limpiarán después de 5 intentos fallidos.", + "appSettings_pathsWillNotBeCleared": "Las rutas no se eliminarán automáticamente.", + "appSettings_autoRouteRotation": "Rotación de Ruta Automática", + "appSettings_autoRouteRotationSubtitle": "Alternar entre las mejores rutas y el modo inundación", + "appSettings_autoRouteRotationEnabled": "Rotación de ruta automática habilitada", + "appSettings_autoRouteRotationDisabled": "Rotación de ruta automática desactivada", + "appSettings_battery": "Batería", + "appSettings_batteryChemistry": "Química de la batería", + "appSettings_batteryChemistryPerDevice": "Configuración por dispositivo ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Conéctate a un dispositivo para elegir", + "appSettings_batteryNmc": "18650 NMC (3.0-4.2V)", + "appSettings_batteryLifepo4": "LiFePO4 (2.6-3.65V)", + "appSettings_batteryLipo": "LiPo (3.0-4.2V)", + "appSettings_mapDisplay": "Visualización del Mapa", + "appSettings_showRepeaters": "Mostrar Repetidores", + "appSettings_showRepeatersSubtitle": "Mostrar nodos de repetidor en el mapa", + "appSettings_showChatNodes": "Mostrar Nodos de Chat", + "appSettings_showChatNodesSubtitle": "Mostrar nodos de chat en el mapa", + "appSettings_showOtherNodes": "Mostrar otros nodos", + "appSettings_showOtherNodesSubtitle": "Mostrar otros tipos de nodo en el mapa", + "appSettings_timeFilter": "Filtro de Tiempo", + "appSettings_timeFilterShowAll": "Mostrar todos los nodos", + "appSettings_timeFilterShowLast": "Mostrar nodos de las últimas {hours} horas", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Filtro de Tiempo del Mapa", + "appSettings_showNodesDiscoveredWithin": "Mostrar nodos descubiertos dentro de:", + "appSettings_allTime": "Todo el tiempo", + "appSettings_lastHour": "Última hora", + "appSettings_last6Hours": "Últimas 6 horas", + "appSettings_last24Hours": "Últimas 24 horas", + "appSettings_lastWeek": "La semana pasada", + "appSettings_offlineMapCache": "Caché de Mapa Offline", + "appSettings_noAreaSelected": "No se ha seleccionado ningún área", + "appSettings_areaSelectedZoom": "Área seleccionada (zoom {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Depurar", + "appSettings_appDebugLogging": "Registro de Depuración de la App", + "appSettings_appDebugLoggingSubtitle": "Registrar mensajes de depuración de la app de registro para solucionar problemas", + "appSettings_appDebugLoggingEnabled": "Registro de depuración de la aplicación habilitado", + "appSettings_appDebugLoggingDisabled": "El registro de depuración de la aplicación está desactivado", + "contacts_title": "Contactos", + "contacts_noContacts": "Aún no hay contactos.", + "contacts_contactsWillAppear": "Los contactos aparecerán cuando los dispositivos anuncien.", + "contacts_searchContacts": "Buscar contactos...", + "contacts_noUnreadContacts": "No contactos sin leer", + "contacts_noContactsFound": "No se encontraron contactos ni grupos.", + "contacts_deleteContact": "Eliminar Contacto", + "contacts_removeConfirm": "Eliminar {contactName} de los contactos?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Gestionar Repetidor", + "contacts_roomLogin": "Inicio de Sala", + "contacts_openChat": "Abrir Chat", + "contacts_editGroup": "Editar Grupo", + "contacts_deleteGroup": "Eliminar Grupo", + "contacts_deleteGroupConfirm": "Eliminar {groupName}?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Nuevo Grupo", + "contacts_groupName": "Nombre del grupo", + "contacts_groupNameRequired": "El nombre del grupo es obligatorio", + "contacts_groupAlreadyExists": "El grupo \"{name}\" ya existe", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Filtrar contactos...", + "contacts_noContactsMatchFilter": "No hay contactos que coincidan con tu filtro", + "contacts_noMembers": "No miembros", + "contacts_lastSeenNow": "Última vez que se vio ahora", + "contacts_lastSeenMinsAgo": "Última vez visto hace {minutes} minutos.", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Última vez que se vio hace 1 hora", + "contacts_lastSeenHoursAgo": "Última vez visto hace {hours} horas.", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Última vez que se vio hace 1 día", + "contacts_lastSeenDaysAgo": "Última vez visto hace {days} días.", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Canales", + "channels_noChannelsConfigured": "No se han configurado canales", + "channels_addPublicChannel": "Añadir Canal Público", + "channels_searchChannels": "Buscar canales...", + "channels_noChannelsFound": "No se encontraron canales", + "channels_channelIndex": "Canal {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Canal con hashtag", + "channels_public": "Público", + "channels_private": "Privado", + "channels_publicChannel": "Canal público", + "channels_privateChannel": "Canal privado", + "channels_editChannel": "Editar canal", + "channels_deleteChannel": "Eliminar canal", + "channels_deleteChannelConfirm": "Eliminar \"{name}\"? Esto no se puede deshacer.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Canal \"{name}\" eliminado", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Añadir Canal", + "channels_channelIndexLabel": "Índice de Canal", + "channels_channelName": "Nombre del canal", + "channels_usePublicChannel": "Usar Canal Público", + "channels_standardPublicPsk": "PSK estándar público", + "channels_pskHex": "PSK (Hex)", + "channels_generateRandomPsk": "Generar PSK aleatorio", + "channels_enterChannelName": "Por favor, introduce un nombre de canal", + "channels_pskMustBe32Hex": "PSK debe ser de 32 caracteres hexadecimales.", + "channels_channelAdded": "Canal \"{name}\" añadido", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Editar Canal {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "Compresión SMAZ", + "channels_channelUpdated": "Canal \"{name}\" actualizado", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "Canal público añadido", + "channels_sortBy": "Ordenar por", + "channels_sortManual": "Manual", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "Últimos mensajes", + "channels_sortUnread": "Sin leer", + "chat_noMessages": "Aún no hay mensajes", + "chat_sendMessageToStart": "Enviar un mensaje para comenzar", + "chat_originalMessageNotFound": "Mensaje original no encontrado", + "chat_replyingTo": "Responder a {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Responder a {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Ubicación", + "chat_sendMessageTo": "Enviar un mensaje a {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Escribe un mensaje...", + "chat_messageTooLong": "Mensaje demasiado largo (máximo {maxBytes} bytes).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Mensaje copiado", + "chat_messageDeleted": "Mensaje borrado", + "chat_retryingMessage": "Reintentando…", + "chat_retryCount": "Reintentar {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "Enviar GIF", + "chat_reply": "Responder", + "chat_addReaction": "Añadir Reacción", + "chat_me": "Yo", + "emojiCategorySmileys": "Emoticones", + "emojiCategoryGestures": "Gestos", + "emojiCategoryHearts": "Corazones", + "emojiCategoryObjects": "Objetos", + "gifPicker_title": "Elegir un GIF", + "gifPicker_searchHint": "Buscar GIFs...", + "gifPicker_poweredBy": "Powered by GIPHY", + "gifPicker_noGifsFound": "No se encontraron GIFs", + "gifPicker_failedLoad": "No se pudo cargar los GIFs", + "gifPicker_failedSearch": "No se encontraron GIFs", + "gifPicker_noInternet": "No hay conexión a internet", + "debugLog_appTitle": "Registro de Depuración de la App", + "debugLog_bleTitle": "Registro de Depuración BLE", + "debugLog_copyLog": "Copiar registro", + "debugLog_clearLog": "Borrar registro", + "debugLog_copied": "Registro de depuración copiado", + "debugLog_bleCopied": "Registro BLE copiado", + "debugLog_noEntries": "Aún no hay registros de depuración.", + "debugLog_enableInSettings": "Habilitar el registro de depuración de la aplicación en la configuración", + "debugLog_frames": "Marcos", + "debugLog_rawLogRx": "Registro Crudo-RX", + "debugLog_noBleActivity": "Aún no hay actividad BLE", + "debugFrame_length": "Longitud del Marco: {count} bytes", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Comando: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Mensaje de Texto:", + "debugFrame_destinationPubKey": "- Destino PubKey: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Marca de tiempo: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Banderas: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- Tipo de texto: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Sencillo", + "debugFrame_text": "- Texto: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Mapeo Hexadecimal:", + "chat_pathManagement": "Gestión de Rutas", + "chat_routingMode": "Modo de enrutamiento", + "chat_autoUseSavedPath": "Auto (usar la ruta guardada)", + "chat_forceFloodMode": "Modo Inundación Forzado", + "chat_recentAckPaths": "Rutas de ACK Recientes (tocar para usar):", + "chat_pathHistoryFull": "El historial de rutas está completo. Eliminar entradas para añadir nuevas.", + "chat_hopSingular": "salta", + "chat_hopPlural": "salta", + "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "Éxitos", + "chat_removePath": "Eliminar ruta", + "chat_noPathHistoryYet": "Aún no hay historial de rutas.\nEnvía un mensaje para descubrir rutas.", + "chat_pathActions": "Acciones de Ruta:", + "chat_setCustomPath": "Establecer Ruta Personalizada", + "chat_setCustomPathSubtitle": "Especificar manualmente la ruta de enrutamiento", + "chat_clearPath": "Limpiar Ruta", + "chat_clearPathSubtitle": "Forzar redescubrimiento en el próximo envío", + "chat_pathCleared": "Ruta eliminada. El siguiente mensaje redescubrirá la ruta.", + "chat_floodModeSubtitle": "Utilizar el interruptor de enrutamiento en la barra de herramientas", + "chat_floodModeEnabled": "El modo de inundación está habilitado. Desactívalo mediante el icono de enrutamiento en la barra de herramientas de la aplicación.", + "chat_fullPath": "Ruta completa", + "chat_pathDetailsNotAvailable": "Los detalles de la ruta aún no están disponibles. Intenta enviar un mensaje para refrescar.", + "chat_pathSetHops": "Ruta establecida: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Guardado localmente. Conéctate para sincronizar.", + "chat_pathDeviceConfirmed": "Dispositivo confirmado.", + "chat_pathDeviceNotConfirmed": "Dispositivo aún no confirmado.", + "chat_type": "Escribe", + "chat_path": "Ruta", + "chat_publicKey": "Clave Pública", + "chat_compressOutgoingMessages": "Comprimir mensajes salientes", + "chat_floodForced": "Inundación (forzada)", + "chat_directForced": "Directo (forzado)", + "chat_hopsForced": "{count} saltos (forzados)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Inundación (automática)", + "chat_direct": "Guardar", + "chat_poiShared": "Punto de Interés Compartido", + "chat_unread": "Sin leer: {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Mapa de Nodos", + "map_noNodesWithLocation": "No hay nodos con datos de ubicación", + "map_nodesNeedGps": "Los nodos necesitan compartir sus coordenadas GPS\npara aparecer en el mapa", + "map_nodesCount": "Nodos: {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Ganchos: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Chat", + "map_repeater": "Repetidor", + "map_room": "Habitación", + "map_sensor": "Sensor", + "map_pinDm": "Pin (DM)", + "map_pinPrivate": "Bloqueo (Privado)", + "map_pinPublic": "Clave (Pública)", + "map_lastSeen": "Última vez que se vio", + "map_disconnectConfirm": "¿Está seguro de que desea desconectarse de este dispositivo?", + "map_from": "De", + "map_source": "Fuente", + "map_flags": "Banderas", + "map_shareMarkerHere": "Compartir marcador aquí", + "map_pinLabel": "Etiqueta de marcador", + "map_label": "Etiqueta", + "map_pointOfInterest": "Punto de interés", + "map_sendToContact": "Enviar a contacto", + "map_sendToChannel": "Enviar a canal", + "map_noChannelsAvailable": "No hay canales disponibles", + "map_publicLocationShare": "Compartir ubicación pública", + "map_publicLocationShareConfirm": "Estás a punto de compartir una ubicación en {channelLabel}. Este canal es público y cualquiera con la PSK puede verlo.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Conéctate a un dispositivo para compartir marcadores", + "map_filterNodes": "Filtrar Nodos", + "map_nodeTypes": "Tipos de nodo", + "map_chatNodes": "Nodos de Chat", + "map_repeaters": "Repetidores", + "map_otherNodes": "Otros Nodos", + "map_keyPrefix": "Prefijo de clave", + "map_filterByKeyPrefix": "Filtrar por prefijo clave", + "map_publicKeyPrefix": "Prefijo de clave pública", + "map_markers": "Marcadores", + "map_showSharedMarkers": "Mostrar marcadores compartidos", + "map_lastSeenTime": "Última vez que se vio", + "map_sharedPin": "Pin compartido", + "map_joinRoom": "Únete a la sala", + "map_manageRepeater": "Gestionar Repetidor", + "mapCache_title": "Caché de Mapa Offline", + "mapCache_selectAreaFirst": "Seleccionar un área para cachear primero", + "mapCache_noTilesToDownload": "No hay azulejos para descargar para este área.", + "mapCache_downloadTilesTitle": "Descargar ficheros", + "mapCache_downloadTilesPrompt": "Descargar {count} ficheros para usar sin conexión?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Descargar", + "mapCache_cachedTiles": "Almacenados {count} azulejos", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Archivados {downloaded} azulejos ({failed} fallidos)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Borrar caché offline", + "mapCache_clearOfflineCachePrompt": "Eliminar todas las baldosas en caché del mapa?", + "mapCache_offlineCacheCleared": "Almacén en caché sin conexión eliminado", + "mapCache_noAreaSelected": "No se ha seleccionado ningún área", + "mapCache_cacheArea": "Área de Caché", + "mapCache_useCurrentView": "Usar Vista Actual", + "mapCache_zoomRange": "Rango de Zoom", + "mapCache_estimatedTiles": "Tiles estimados: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Descargados {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Descargar Mosaicos", + "mapCache_clearCacheButton": "Borrar Caché", + "mapCache_failedDownloads": "Descargas fallidas: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Hace un momento", + "time_minutesAgo": "{minutes} minutos hace.", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours}h hace", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} días hace", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "hora", + "time_hours": "horas", + "time_day": "día", + "time_days": "días", + "time_week": "semana", + "time_weeks": "semanas", + "time_month": "mes", + "time_months": "meses", + "time_minutes": "minutos", + "time_allTime": "Todas las veces", + "dialog_disconnect": "Desconectar", + "dialog_disconnectConfirm": "¿Está seguro de que desea desconectarse de este dispositivo?", + "login_repeaterLogin": "Iniciar sesión en el Repetidor", + "login_roomLogin": "Inicio de Sala", + "login_password": "Contraseña", + "login_enterPassword": "Introducir contraseña", + "login_savePassword": "Guardar contraseña", + "login_savePasswordSubtitle": "La contraseña se almacenará de forma segura en este dispositivo.", + "login_repeaterDescription": "Ingrese la contraseña del repetidor para acceder a la configuración y el estado.", + "login_roomDescription": "Ingrese la contraseña de la sala para acceder a la configuración y el estado.", + "login_routing": "Enrutamiento", + "login_routingMode": "Modo de enrutamiento", + "login_autoUseSavedPath": "Auto (usar la ruta guardada)", + "login_forceFloodMode": "Activar Modo Inundación Forzada", + "login_managePaths": "Gestionar Rutas", + "login_login": "Iniciar sesión", + "login_attempt": "Intentar {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Inicio fallido: {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Recargar", + "common_clear": "Borrar", + "path_currentPath": "Ruta actual: {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Usando {count} {count, plural, =1{hop} other{hops}} ruta", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Introducir Ruta Personalizada", + "path_currentPathLabel": "Ruta actual", + "path_hexPrefixInstructions": "Introduzca los prefijos hexadecimales de 2 caracteres para cada salto, separados por comas.", + "path_hexPrefixExample": "Ejemplo: A1,F2,3C (cada nodo utiliza el primer byte de su clave pública).", + "path_labelHexPrefixes": "Prefijos hexadecimales", + "path_helperMaxHops": "Máximo 64 saltos. Cada prefijo tiene 2 caracteres hexadecimales (1 byte).", + "path_selectFromContacts": "O seleccionar de contactos:", + "path_noRepeatersFound": "No se encontraron repetidores ni servidores de sala.", + "path_customPathsRequire": "Las rutas personalizadas requieren saltos intermedios que pueden transmitir mensajes.", + "path_invalidHexPrefixes": "Prefijos hexadecimales inválidos: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "La ruta es demasiado larga. Se permiten un máximo de 64 saltos.", + "path_setPath": "Establecer Ruta", + "repeater_management": "Gestión de Repetidores", + "repeater_managementTools": "Herramientas de Gestión", + "repeater_status": "Estado", + "repeater_statusSubtitle": "Ver el estado, las estadísticas y los vecinos del repetidor", + "repeater_telemetry": "Telemetry", + "repeater_telemetrySubtitle": "Ver la telemetría de los sensores y las estadísticas del sistema", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Enviar comandos al repetidor", + "repeater_settings": "Configuración", + "repeater_settingsSubtitle": "Configurar parámetros del repetidor", + "repeater_statusTitle": "Estado del Repetidor", + "repeater_routingMode": "Modo de enrutamiento", + "repeater_autoUseSavedPath": "Auto (usar la ruta guardada)", + "repeater_forceFloodMode": "Modo Inundación Forzado", + "repeater_pathManagement": "Gestión de rutas", + "repeater_refresh": "Actualizar", + "repeater_statusRequestTimeout": "Solicitud de estado caducó.", + "repeater_errorLoadingStatus": "Error al cargar el estado: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Información del sistema", + "repeater_battery": "Batería", + "repeater_clockAtLogin": "Reloj (al inicio de sesión)", + "repeater_uptime": "Tiempo de actividad", + "repeater_queueLength": "Longitud de la cola", + "repeater_debugFlags": "Marcadores de Depuración", + "repeater_radioStatistics": "Estadísticas de Radio", + "repeater_lastRssi": "Último RSSI", + "repeater_lastSnr": "Último SNR", + "repeater_noiseFloor": "Nivel de Ruido", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Estadísticas del Paquete", + "repeater_sent": "Enviado", + "repeater_received": "Recibido", + "repeater_duplicates": "Duplicados", + "repeater_daysHoursMinsSecs": "{days} días {hours}h {minutes}m {seconds}s", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Total: {total}, Inundación: {flood}, Directo: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Total: {total}, Inundación: {flood}, Directo: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Inundación: {flood}, Directo: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Total: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Configuración del Repetidor", + "repeater_basicSettings": "Configuración Básica", + "repeater_repeaterName": "Nombre del Repetidor", + "repeater_repeaterNameHelper": "Mostrar nombre para este repetidor", + "repeater_adminPassword": "Contraseña de Administrador", + "repeater_adminPasswordHelper": "Contraseña de acceso completo", + "repeater_guestPassword": "Contraseña de invitado", + "repeater_guestPasswordHelper": "Acceso de solo lectura con contraseña", + "repeater_radioSettings": "Configuración de Radio", + "repeater_frequencyMhz": "Frecuencia (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Potencia", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Ancho de banda", + "repeater_spreadingFactor": "Factor de propagación", + "repeater_codingRate": "Tasa de Programación", + "repeater_locationSettings": "Configuración de Ubicación", + "repeater_latitude": "Latitud", + "repeater_latitudeHelper": "Grados decimales (por ejemplo, 37.7749)", + "repeater_longitude": "Longitud", + "repeater_longitudeHelper": "Grados decimales (por ejemplo, -122.4194)", + "repeater_features": "Características", + "repeater_packetForwarding": "Enrutamiento de Paquetes", + "repeater_packetForwardingSubtitle": "Habilitar el repetidor para reenviar paquetes", + "repeater_guestAccess": "Acceso de Invitados", + "repeater_guestAccessSubtitle": "Permitir acceso de invitado en solo lectura", + "repeater_privacyMode": "Modo Privacidad", + "repeater_privacyModeSubtitle": "Ocultar nombre/ubicación en anuncios", + "repeater_advertisementSettings": "Configuración de Anuncios", + "repeater_localAdvertInterval": "Intervalo de Anuncio Local", + "repeater_localAdvertIntervalMinutes": "{minutes} minutos", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Intervalo de Anuncio de Inundación", + "repeater_floodAdvertIntervalHours": "{hours} horas", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Intervalo de Anuncio Cifrado", + "repeater_dangerZone": "Zona de Peligro", + "repeater_rebootRepeater": "Reiniciar Repetidor", + "repeater_rebootRepeaterSubtitle": "Reiniciar el dispositivo repetidor", + "repeater_rebootRepeaterConfirm": "¿Está seguro de que desea reiniciar este repetidor?", + "repeater_regenerateIdentityKey": "Regenerar Clave de Identidad", + "repeater_regenerateIdentityKeySubtitle": "Generar nueva pareja de clave pública/privada", + "repeater_regenerateIdentityKeyConfirm": "Esto generará una nueva identidad para el repetidor. Continuar?", + "repeater_eraseFileSystem": "Borrar Sistema de Archivos", + "repeater_eraseFileSystemSubtitle": "Formatear el sistema de archivos del repetidor", + "repeater_eraseFileSystemConfirm": "ADVERTENCIA: Esto borrará todos los datos del repetidor. ¡Esto no se puede deshacer!", + "repeater_eraseSerialOnly": "Borrar solo está disponible a través de la consola serial.", + "repeater_commandSent": "Comando enviado: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Error al enviar el comando: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "Confirmar", + "repeater_settingsSaved": "Guardado de ajustes exitoso", + "repeater_errorSavingSettings": "Error al guardar la configuración: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Actualizar Configuración Básica", + "repeater_refreshRadioSettings": "Actualizar Ajustes de Radio", + "repeater_refreshTxPower": "Actualizar TX de energía", + "repeater_refreshLocationSettings": "Actualizar Configuración de Ubicación", + "repeater_refreshPacketForwarding": "Actualizar Enrutamiento de Paquetes", + "repeater_refreshGuestAccess": "Actualizar Acceso Invitados", + "repeater_refreshPrivacyMode": "Actualizar Modo Privacidad", + "repeater_refreshAdvertisementSettings": "Actualizar Configuración de Anuncios", + "repeater_refreshed": "{label} actualizado", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Error al refrescar {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Repetidor CLI", + "repeater_debugNextCommand": "Siguiente Comando de Depuración", + "repeater_commandHelp": "Ayuda", + "repeater_clearHistory": "Borrar historial", + "repeater_noCommandsSent": "Aún no se han enviado comandos.", + "repeater_typeCommandOrUseQuick": "Escriba un comando a continuación o use comandos rápidos", + "repeater_enterCommandHint": "Escribir comando...", + "repeater_previousCommand": "Comando anterior", + "repeater_nextCommand": "Siguiente comando", + "repeater_enterCommandFirst": "Escriba un comando primero", + "repeater_cliCommandFrameTitle": "Marco de Comando CLI", + "repeater_cliCommandError": "Error: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Obtener Nombre", + "repeater_cliQuickGetRadio": "Obtener Radio", + "repeater_cliQuickGetTx": "Obtener TX", + "repeater_cliQuickNeighbors": "Vecinos", + "repeater_cliQuickVersion": "Versión", + "repeater_cliQuickAdvertise": "Anunciar", + "repeater_cliQuickClock": "Reloj", + "repeater_cliHelpAdvert": "Envía un paquete de publicidad", + "repeater_cliHelpReboot": "Reinicia el dispositivo. (ten en cuenta, es normal que aparezca 'Timeout')", + "repeater_cliHelpClock": "Muestra la hora actual según el reloj del dispositivo.", + "repeater_cliHelpPassword": "Establece una nueva contraseña de administrador para el dispositivo.", + "repeater_cliHelpVersion": "Muestra la versión del dispositivo y la fecha de compilación del firmware.", + "repeater_cliHelpClearStats": "Reinicia varios contadores de estadísticas a cero.", + "repeater_cliHelpSetAf": "Establece el factor de tiempo de aire.", + "repeater_cliHelpSetTx": "Establece la potencia de transmisión LoRa en dBm (reboot para aplicar).", + "repeater_cliHelpSetRepeat": "Habilita o deshabilita el rol del repetidor para este nodo.", + "repeater_cliHelpSetAllowReadOnly": "(Servidor de la sala) Si está \"activado\", entonces el inicio de sesión con una contraseña en blanco estará permitido, pero no se podrá publicar en la sala. (solo lectura).", + "repeater_cliHelpSetFloodMax": "Establece el número máximo de saltos de paquetes de inundación entrantes (si es >= máximo, el paquete no se enruta).", + "repeater_cliHelpSetIntThresh": "Establece el Umbral de Interferencia (en dB). El valor predeterminado es 14. Establecerlo en 0 desactiva la detección de interferencias del canal.", + "repeater_cliHelpSetAgcResetInterval": "Establece el intervalo para restablecer el Control Automático de Ganancia. Establecer en 0 para desactivarlo.", + "repeater_cliHelpSetMultiAcks": "Habilita o deshabilita la función de 'ACKs dobles'.", + "repeater_cliHelpSetAdvertInterval": "Establece el intervalo del temporizador en minutos para enviar un paquete de anuncio local (sin salto). Establecer en 0 para desactivarlo.", + "repeater_cliHelpSetFloodAdvertInterval": "Establece el intervalo del temporizador en horas para enviar un paquete de anuncio masivo. Establecer en 0 para desactivarlo.", + "repeater_cliHelpSetGuestPassword": "Establece/actualiza la contraseña del invitado. (para repetidores, los inicios de sesión de invitado pueden enviar la solicitud \"Obtener Estadísticas\")", + "repeater_cliHelpSetName": "Establece el nombre del anuncio.", + "repeater_cliHelpSetLat": "Establece la latitud del mapa de publicidad. (grados decimales)", + "repeater_cliHelpSetLon": "Establece la longitud del mapa de la publicidad. (grados decimales)", + "repeater_cliHelpSetRadio": "Establece parámetros de radio completamente nuevos y los guarda en las preferencias. Requiere un comando \"reboot\" para aplicarlos.", + "repeater_cliHelpSetRxDelay": "Configura (experimental) la base para aplicar un ligero retraso a los paquetes recibidos, según la fuerza de la señal/puntuación. Establece en 0 para desactivar.", + "repeater_cliHelpSetTxDelay": "Establece un factor multiplicado con el tiempo de aire para un paquete de modo de inundación y con un sistema de ranura aleatorio, para retrasar su reenvío (para disminuir la probabilidad de colisiones).", + "repeater_cliHelpSetDirectTxDelay": "Igual que txdelay, pero para aplicar un retraso aleatorio a la transferencia de paquetes en modo directo.", + "repeater_cliHelpSetBridgeEnabled": "Habilitar/Deshabilitar puente.", + "repeater_cliHelpSetBridgeDelay": "Establecer retraso antes de retransmitir paquetes.", + "repeater_cliHelpSetBridgeSource": "Elige si el puente retransmitirá paquetes recibidos o paquetes transmitidos.", + "repeater_cliHelpSetBridgeBaud": "Establecer la velocidad de baudios del enlace serial para los puentes rs232.", + "repeater_cliHelpSetBridgeSecret": "Establecer secreto de puente para puentes espnow.", + "repeater_cliHelpSetAdcMultiplier": "Establece un factor personalizado para ajustar el voltaje de la batería reportado (solo soportado en selectas placas).", + "repeater_cliHelpTempRadio": "Establece parámetros de radio temporales para el número dado de minutos, volviendo a los parámetros de radio originales posteriormente. (no guarda en preferencias).", + "repeater_cliHelpSetPerm": "Modifica el ACL. Elimina la entrada coincidente (por prefijo de pubkey) si \"permissions\" es cero. Añade una nueva entrada si el pubkey-hex tiene longitud completa y no está actualmente en el ACL. Actualiza la entrada mediante el prefijo de pubkey coincidente. Los bits de permiso varían según el rol del firmware, pero los dos bits inferiores son: 0 (Invitado), 1 (Solo lectura), 2 (Lectura/escritura), 3 (Administrador).", + "repeater_cliHelpGetBridgeType": "Obtiene tipo de puente ninguno, rs232, espnow", + "repeater_cliHelpLogStart": "Inicia el registro de paquetes en el sistema de archivos.", + "repeater_cliHelpLogStop": "Detener el registro de paquetes al sistema de archivos.", + "repeater_cliHelpLogErase": "Elimina los registros del paquete del sistema de archivos.", + "repeater_cliHelpNeighbors": "Muestra una lista de otros nodos repetidores escuchados a través de anuncios de un solo salto. Cada línea es id-prefijo-hex:marca de tiempo:times-snr-4", + "repeater_cliHelpNeighborRemove": "Elimina la primera entrada coincidente (por prefijo de pubkey (hex)) de la lista de vecinos.", + "repeater_cliHelpRegion": "(solo serie) Lista todas las regiones definidas y los permisos de inundación actuales.", + "repeater_cliHelpRegionLoad": "NOTA: este es un invocación multi-comando especial. Cada comando subsiguiente es un nombre de región (indentado con espacios para indicar la jerarquía padre, con un espacio mínimo). Terminado enviando una línea en blanco/comando.", + "repeater_cliHelpRegionGet": "Busca la región con el prefijo de nombre dado (o \"\" para el ámbito global). Responde con \"-> nombre-región (nombre-padre) 'F'\"", + "repeater_cliHelpRegionPut": "Agrega o actualiza una definición de región con el nombre dado.", + "repeater_cliHelpRegionRemove": "Elimina una definición de región con el nombre dado. (debe coincidir exactamente y no tener regiones hijas)", + "repeater_cliHelpRegionAllowf": "Establece el permiso de 'F'lujo para la región dada. ('' para el ámbito global/legado)", + "repeater_cliHelpRegionDenyf": "Elimina el permiso de 'F'lood para la región especificada. (NOTA: en esta etapa NO se recomienda utilizarlo en el ámbito global/legado!!)", + "repeater_cliHelpRegionHome": "Responde con la región 'home' actual. (Aún no se ha aplicado en ninguna parte, reservado para el futuro).", + "repeater_cliHelpRegionHomeSet": "Establece la región 'hogar'.", + "repeater_cliHelpRegionSave": "Persiste la lista/mapa de regiones al almacenamiento.", + "repeater_cliHelpGps": "Muestra el estado del GPS. Cuando el GPS está apagado, responde solo con \"apagado\", si está encendido, responde con \"encendido\", estado, fijación, número de satélites.", + "repeater_cliHelpGpsOnOff": "Activa o desactiva el modo GPS.", + "repeater_cliHelpGpsSync": "Sincroniza la hora del nodo con el reloj GPS.", + "repeater_cliHelpGpsSetLoc": "Establece la posición del nodo a las coordenadas GPS y guarda las preferencias.", + "repeater_cliHelpGpsAdvert": "Da la configuración de la publicidad del nodo de ubicación:\n- ninguno: no incluir la ubicación en las publicidad\n- compartir: compartir la ubicación GPS (del SensorManager)\n- preferencias: publicidad la ubicación almacenada en preferencias", + "repeater_cliHelpGpsAdvertSet": "Configura la configuración de la publicidad de la ubicación.", + "repeater_commandsListTitle": "Lista de comandos", + "repeater_commandsListNote": "NOTA: para los diversos comandos \"set...\", también existe un comando \"get...\".", + "repeater_general": "General", + "repeater_settingsCategory": "Configuración", + "repeater_bridge": "Puente", + "repeater_logging": "Registrando", + "repeater_neighborsRepeaterOnly": "Vecinos (solo repetidor)", + "repeater_regionManagementRepeaterOnly": "Gestión de Regiones (solo Repetidor)", + "repeater_regionNote": "Se han introducido los comandos de región para gestionar las definiciones y permisos de la región.", + "repeater_gpsManagement": "Gestión de GPS", + "repeater_gpsNote": "Se ha introducido un comando GPS para gestionar temas relacionados con la ubicación.", + "telemetry_receivedData": "Datos de Telemetría Recibidos", + "telemetry_requestTimeout": "Solicitud de telemetría ha expirado.", + "telemetry_errorLoading": "Error al cargar la telemetría: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "No hay datos de telemetría disponibles.", + "telemetry_channelTitle": "Canal {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Batería", + "telemetry_voltageLabel": "Voltaje", + "telemetry_mcuTemperatureLabel": "Temperatura del MCU", + "telemetry_temperatureLabel": "Temperatura", + "telemetry_currentLabel": "Actual", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Ruta del Paquete", + "channelPath_viewMap": "Ver mapa", + "channelPath_otherObservedPaths": "Otros caminos observados", + "channelPath_repeaterHops": "Saltos del Repetidor", + "channelPath_noHopDetails": "Los detalles del paquete no están disponibles.", + "channelPath_messageDetails": "Detalles del mensaje", + "channelPath_senderLabel": "Remitente", + "channelPath_timeLabel": "Tiempo", + "channelPath_repeatsLabel": "Repetir", + "channelPath_pathLabel": "Ruta {index}", + "channelPath_observedLabel": "Observado", + "channelPath_observedPathTitle": "Ruta observada {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "No datos de ubicación", + "channelPath_timeWithDate": "{day}/{month} a las {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Desconocido", + "channelPath_floodPath": "Inundación", + "channelPath_directPath": "Guardar", + "channelPath_observedZeroOf": "0 de {total} saltos", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} de {total} saltos", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Mapa de Rutas", + "channelPath_noRepeaterLocations": "No hay ubicaciones disponibles para el repetidor en esta ruta.", + "channelPath_primaryPath": "Ruta {index} (Principal)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Ruta", + "channelPath_observedPathHeader": "Ruta Observada", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "No hay detalles de salto disponibles para este paquete.", + "channelPath_unknownRepeater": "Repetidor Desconocido", + "listFilter_tooltip": "Filtrar y ordenar", + "listFilter_sortBy": "Ordenar por", + "listFilter_latestMessages": "Últimos mensajes", + "listFilter_heardRecently": "Escuchado recientemente", + "listFilter_az": "A-Z", + "listFilter_filters": "Filtros", + "listFilter_all": "Todas", + "listFilter_users": "Usuarios", + "listFilter_repeaters": "Repetidores", + "listFilter_roomServers": "Servidores de la sala", + "listFilter_unreadOnly": "Solo sin leer", + "listFilter_newGroup": "Nuevo grupo" +} diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb new file mode 100644 index 0000000..4b8af01 --- /dev/null +++ b/lib/l10n/app_fr.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "fr", + "appTitle": "MeshCore Open", + "nav_contacts": "Contacts", + "nav_channels": "Canaux", + "nav_map": "Carte", + "common_cancel": "Annuler", + "common_connect": "Connecter", + "common_unknownDevice": "Appareil inconnu", + "common_save": "Enregistrer", + "common_delete": "Supprimer", + "common_close": "Fermer", + "common_edit": "Modifier", + "common_add": "Ajouter", + "common_settings": "Paramètres", + "common_disconnect": "Déconnecter", + "common_connected": "Connecté", + "common_disconnected": "Déconnecté", + "common_create": "Créer", + "common_continue": "Continuer", + "common_share": "Partager", + "common_copy": "Copier", + "common_retry": "Réessayer", + "common_hide": "Masquer", + "common_remove": "Supprimer", + "common_enable": "Activer", + "common_disable": "Désactiver", + "common_reboot": "Redémarrer", + "common_loading": "Chargement...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Recherche de périphériques...", + "scanner_connecting": "Connexion en cours...", + "scanner_disconnecting": "Déconnexion...", + "scanner_notConnected": "Non connecté", + "scanner_connectedTo": "Connecté à {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Recherche des appareils MeshCore...", + "scanner_tapToScan": "Appuyez sur Scanner pour trouver les appareils MeshCore", + "scanner_connectionFailed": "Échec de la connexion : {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Arrêter", + "scanner_scan": "Scanner", + "device_quickSwitch": "Basculement rapide", + "device_meshcore": "MeshCore", + "settings_title": "Paramètres", + "settings_deviceInfo": "Informations du périphérique", + "settings_appSettings": "Paramètres de l'application", + "settings_appSettingsSubtitle": "Notifications, messagerie et préférences de carte", + "settings_nodeSettings": "Paramètres du nœud", + "settings_nodeName": "Nom du nœud", + "settings_nodeNameNotSet": "Non défini", + "settings_nodeNameHint": "Entrer le nom du nœud", + "settings_nodeNameUpdated": "Nom mis à jour", + "settings_radioSettings": "Paramètres Radio", + "settings_radioSettingsSubtitle": "Fréquence, puissance, facteur d'espacement", + "settings_radioSettingsUpdated": "Paramètres radio mis à jour", + "settings_location": "Emplacement", + "settings_locationSubtitle": "Coordonnées GPS", + "settings_locationUpdated": "Emplacement mis à jour", + "settings_locationBothRequired": "Entrez la latitude et la longitude.", + "settings_locationInvalid": "Latitude ou longitude invalide.", + "settings_latitude": "Latitude", + "settings_longitude": "Longitude", + "settings_privacyMode": "Mode de confidentialité", + "settings_privacyModeSubtitle": "Cacher le nom/l'emplacement dans les publicités", + "settings_privacyModeToggle": "Activer le mode confidentialité pour masquer votre nom et votre localisation dans les publicités.", + "settings_privacyModeEnabled": "Mode de confidentialité activé", + "settings_privacyModeDisabled": "Mode de confidentialité désactivé", + "settings_actions": "Actions", + "settings_sendAdvertisement": "Envoyer la publicité", + "settings_sendAdvertisementSubtitle": "Présence diffusée maintenant", + "settings_advertisementSent": "Annonce envoyée", + "settings_syncTime": "Temps de synchronisation", + "settings_syncTimeSubtitle": "Définir l'heure de l'appareil sur l'heure du téléphone.", + "settings_timeSynchronized": "Synchronisation temporelle", + "settings_refreshContacts": "Rafraîchir les Contacts", + "settings_refreshContactsSubtitle": "Recharger la liste des contacts depuis l'appareil", + "settings_rebootDevice": "Réinitialiser l'appareil", + "settings_rebootDeviceSubtitle": "Redémarrer l'appareil MeshCore", + "settings_rebootDeviceConfirm": "Êtes-vous sûr de vouloir redémarrer l'appareil ? Vous serez déconnecté.", + "settings_debug": "Déboguer", + "settings_bleDebugLog": "Journal de débogage BLE", + "settings_bleDebugLogSubtitle": "Commandes BLE, réponses et données brutes", + "settings_appDebugLog": "Journal de débogage de l'application", + "settings_appDebugLogSubtitle": "Messages de débogage de l'application", + "settings_about": "À propos", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "Projet MeshCore Open Source 2026", + "settings_aboutDescription": "Un client Flutter open source pour les appareils de réseau mesh MeshCore LoRa.", + "settings_infoName": "Nom", + "settings_infoId": "ID", + "settings_infoStatus": "État", + "settings_infoBattery": "Batterie", + "settings_infoPublicKey": "Clé Publique", + "settings_infoContactsCount": "Nombre de contacts", + "settings_infoChannelCount": "Nombre de canaux", + "settings_presets": "Préréglages", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Fréquence (MHz)", + "settings_frequencyHelper": "300,0 - 2 500,0", + "settings_frequencyInvalid": "Fréquence invalide (300-2500 MHz)", + "settings_bandwidth": "Bande passante", + "settings_spreadingFactor": "Facteur de répartition", + "settings_codingRate": "Taux de codage", + "settings_txPower": "TX Puissance (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Puissance TX invalide (0-22 dBm)", + "settings_longRange": "Portée Longue", + "settings_fastSpeed": "Vitesse Rapide", + "settings_error": "Erreur : {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "Paramètres de l'application", + "appSettings_appearance": "Apparence", + "appSettings_theme": "Thème", + "appSettings_themeSystem": "Défaut système", + "appSettings_themeLight": "Lumière", + "appSettings_themeDark": "Sombre", + "appSettings_language": "Langue", + "appSettings_languageSystem": "Par défaut du système", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Notifications", + "appSettings_enableNotifications": "Activer les Notifications", + "appSettings_enableNotificationsSubtitle": "Recevoir des notifications pour les messages et les publicités", + "appSettings_notificationPermissionDenied": "Permission de notification refusée", + "appSettings_notificationsEnabled": "Notifications activées", + "appSettings_notificationsDisabled": "Notifications désactivées", + "appSettings_messageNotifications": "Notifications de Messages", + "appSettings_messageNotificationsSubtitle": "Afficher une notification lors de la réception de nouveaux messages", + "appSettings_channelMessageNotifications": "Notifications des Messages de Canal", + "appSettings_channelMessageNotificationsSubtitle": "Afficher une notification lors de la réception des messages de canal", + "appSettings_advertisementNotifications": "Notifications publicitaires", + "appSettings_advertisementNotificationsSubtitle": "Afficher une notification lors de la découverte de nouveaux nœuds", + "appSettings_messaging": "Messagerie", + "appSettings_clearPathOnMaxRetry": "Effacer le chemin sur Max Retry", + "appSettings_clearPathOnMaxRetrySubtitle": "Réinitialiser le chemin de contact après 5 tentatives d'envoi infructueuses", + "appSettings_pathsWillBeCleared": "Les chemins seront effacés après 5 tentatives infructueuses.", + "appSettings_pathsWillNotBeCleared": "Les chemins ne seront pas effacés automatiquement.", + "appSettings_autoRouteRotation": "Rotation de l'itinéraire automatique", + "appSettings_autoRouteRotationSubtitle": "Alterner entre les meilleurs chemins et le mode inondation", + "appSettings_autoRouteRotationEnabled": "Rotation du routage automatique activée", + "appSettings_autoRouteRotationDisabled": "Rotation de l'itinéraire automatique désactivée", + "appSettings_battery": "Batterie", + "appSettings_batteryChemistry": "Chimie de la batterie", + "appSettings_batteryChemistryPerDevice": "Définir par appareil ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Connectez un appareil pour choisir", + "appSettings_batteryNmc": "18650 NMC (3,0-4,2V)", + "appSettings_batteryLifepo4": "LiFePO4 (2,6-3,65V)", + "appSettings_batteryLipo": "LiPo (3,0-4,2V)", + "appSettings_mapDisplay": "Affichage de la carte", + "appSettings_showRepeaters": "Afficher les répétiteurs", + "appSettings_showRepeatersSubtitle": "Afficher les nœuds répétiteurs sur la carte", + "appSettings_showChatNodes": "Afficher les nœuds de discussion", + "appSettings_showChatNodesSubtitle": "Afficher les nœuds de chat sur la carte", + "appSettings_showOtherNodes": "Afficher d'autres nœuds", + "appSettings_showOtherNodesSubtitle": "Afficher d'autres types de nœuds sur la carte", + "appSettings_timeFilter": "Filtre du temps", + "appSettings_timeFilterShowAll": "Afficher tous les nœuds", + "appSettings_timeFilterShowLast": "Afficher les nœuds des {hours} dernières heures", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Filtre du Temps de la Carte", + "appSettings_showNodesDiscoveredWithin": "Afficher les nœuds découverts dans :", + "appSettings_allTime": "Tout le temps", + "appSettings_lastHour": "Dernière heure", + "appSettings_last6Hours": "Dernières 6 heures", + "appSettings_last24Hours": "Dernières 24 heures", + "appSettings_lastWeek": "La semaine dernière", + "appSettings_offlineMapCache": "Cache de Carte Hors Ligne", + "appSettings_noAreaSelected": "Aucune zone sélectionnée", + "appSettings_areaSelectedZoom": "Zone sélectionnée (zoom {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Déboguer", + "appSettings_appDebugLogging": "Journalisation de débogage de l'application", + "appSettings_appDebugLoggingSubtitle": "Enregistrez les messages de débogage de l'application Log pour le dépannage.", + "appSettings_appDebugLoggingEnabled": "Journalisation de débogage de l'application activée", + "appSettings_appDebugLoggingDisabled": "Le débogage de l'application est désactivé.", + "contacts_title": "Contacts", + "contacts_noContacts": "Aucun contact trouvé.", + "contacts_contactsWillAppear": "Les contacts apparaîtront lorsque les appareils font leur annonce.", + "contacts_searchContacts": "Rechercher des contacts...", + "contacts_noUnreadContacts": "Aucun contact non lu", + "contacts_noContactsFound": "Aucun contact ou groupe trouvé.", + "contacts_deleteContact": "Supprimer le contact", + "contacts_removeConfirm": "Supprimer {contactName} des contacts ?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Gérer le répétiteur", + "contacts_roomLogin": "Connexion Salle", + "contacts_openChat": "Ouverture du Chat", + "contacts_editGroup": "Modifier le groupe", + "contacts_deleteGroup": "Supprimer le groupe", + "contacts_deleteGroupConfirm": "Supprimer {groupName}?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Nouvelle Groupe", + "contacts_groupName": "Nom du groupe", + "contacts_groupNameRequired": "Le nom du groupe est obligatoire.", + "contacts_groupAlreadyExists": "Le groupe \"{name}\" existe déjà.", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Filtrer les contacts...", + "contacts_noContactsMatchFilter": "Aucun contact ne correspond à votre filtre.", + "contacts_noMembers": "Aucun membre", + "contacts_lastSeenNow": "Dernière fois vu maintenant", + "contacts_lastSeenMinsAgo": "Dernière fois vu il y a {minutes} minutes.", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Dernière fois vu il y a 1 heure.", + "contacts_lastSeenHoursAgo": "Dernière fois vu il y a {hours} heures.", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Dernière fois vu il y a 1 jour", + "contacts_lastSeenDaysAgo": "Dernière activité il y a {days} jours", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Canaux", + "channels_noChannelsConfigured": "Aucun canal configuré", + "channels_addPublicChannel": "Ajouter un canal public", + "channels_searchChannels": "Rechercher des canaux...", + "channels_noChannelsFound": "Aucun canal trouvé", + "channels_channelIndex": "Canal {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Canal avec hashtag", + "channels_public": "Public", + "channels_private": "Privé", + "channels_publicChannel": "Canal public", + "channels_privateChannel": "Canal privé", + "channels_editChannel": "Modifier le canal", + "channels_deleteChannel": "Supprimer le canal", + "channels_deleteChannelConfirm": "Supprimer {name}? Cela ne peut pas être annulé.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Le canal \"{name}\" a été supprimé", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Ajouter un Canal", + "channels_channelIndexLabel": "Index de canal", + "channels_channelName": "Nom du canal", + "channels_usePublicChannel": "Utiliser le canal public", + "channels_standardPublicPsk": "PSK public standard", + "channels_pskHex": "PSK (Hex)", + "channels_generateRandomPsk": "Générer une clé de modulation PSK aléatoire", + "channels_enterChannelName": "Veuillez entrer un nom de canal", + "channels_pskMustBe32Hex": "Le PKS doit être composé de 32 caractères hexadécimaux.", + "channels_channelAdded": "Le canal \"{name}\" a été ajouté", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Modifier le Canal {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "Compression SMAZ", + "channels_channelUpdated": "Le canal \"{name}\" a été mis à jour", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "Le canal public a été ajouté", + "channels_sortBy": "Trier par", + "channels_sortManual": "Manuel", + "channels_sortAZ": "A à Z", + "channels_sortLatestMessages": "Dernières messages", + "channels_sortUnread": "Non lu", + "chat_noMessages": "Aucun message pour le moment.", + "chat_sendMessageToStart": "Envoyer un message pour commencer", + "chat_originalMessageNotFound": "Message d'origine non trouvé", + "chat_replyingTo": "Répondre à {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Répondre à {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Emplacement", + "chat_sendMessageTo": "Envoyer un message à {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Saisir un message...", + "chat_messageTooLong": "Message trop long (max {maxBytes} octets).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Message copié", + "chat_messageDeleted": "Message supprimé", + "chat_retryingMessage": "Tentative de récupération.", + "chat_retryCount": "Réessayer {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "Envoyer GIF", + "chat_reply": "Répondre", + "chat_addReaction": "Ajouter une Réaction", + "chat_me": "Moi", + "emojiCategorySmileys": "Émojis", + "emojiCategoryGestures": "Gestes", + "emojiCategoryHearts": "Cœurs", + "emojiCategoryObjects": "Objets", + "gifPicker_title": "Choisir un GIF", + "gifPicker_searchHint": "Rechercher des GIF...", + "gifPicker_poweredBy": "Propulsé par GIPHY", + "gifPicker_noGifsFound": "Aucun GIF trouvé", + "gifPicker_failedLoad": "Impossible de charger les GIFs", + "gifPicker_failedSearch": "Recherche de GIFs échouée", + "gifPicker_noInternet": "Aucune connexion internet", + "debugLog_appTitle": "Journal de débogage de l'application", + "debugLog_bleTitle": "Journal de débogage BLE", + "debugLog_copyLog": "Copier le journal", + "debugLog_clearLog": "Effacer le journal", + "debugLog_copied": "Journal de débogage copié", + "debugLog_bleCopied": "Journal BLE copié", + "debugLog_noEntries": "Aucun journal de débogage pour le moment.", + "debugLog_enableInSettings": "Activer le débogage de l'application dans les paramètres", + "debugLog_frames": "Cadres", + "debugLog_rawLogRx": "Enregistrement brut - RX", + "debugLog_noBleActivity": "Pas d'activité BLE enregistrée pour le moment.", + "debugFrame_length": "Longueur du cadre : {count} octets", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Commande : 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Message :", + "debugFrame_destinationPubKey": "- Destination PubKey: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Timestamp : {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Indicateurs : 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- Type de texte : {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Simple", + "debugFrame_text": "- Texte : \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Vidéo de Dump Hexadécimal :", + "chat_pathManagement": "Gestion des chemins", + "chat_routingMode": "Mode de routage", + "chat_autoUseSavedPath": "Auto (utiliser le chemin sauvegardé)", + "chat_forceFloodMode": "Mode Inondation Forcée", + "chat_recentAckPaths": "Chemins ACK récents (touchez pour utiliser) :", + "chat_pathHistoryFull": "L'historique du chemin est plein. Supprimez les entrées pour en ajouter de nouvelles.", + "chat_hopSingular": "Sautez", + "chat_hopPlural": "sautez", + "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "Succès", + "chat_removePath": "Supprimer le chemin", + "chat_noPathHistoryYet": "Aucune historique de parcours disponible.\nEnvoyez un message pour découvrir les parcours.", + "chat_pathActions": "Actions du chemin :", + "chat_setCustomPath": "Définir un chemin personnalisé", + "chat_setCustomPathSubtitle": "Spécifier manuellement le chemin de routage", + "chat_clearPath": "Effacer le chemin", + "chat_clearPathSubtitle": "Forcer la redécouverte lors de la prochaine envoi", + "chat_pathCleared": "Le chemin est dégagé. Le prochain message redécouvrira le tracé.", + "chat_floodModeSubtitle": "Utiliser le commutateur de routage dans la barre d'application", + "chat_floodModeEnabled": "Le mode inondation est activé. Réactiver via l'icône de routage dans la barre d'outils.", + "chat_fullPath": "Chemin complet", + "chat_pathDetailsNotAvailable": "Les détails du chemin ne sont pas encore disponibles. Essayez d'envoyer un message pour rafraîchir.", + "chat_pathSetHops": "Chemin défini : {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Sauvegardé localement. Connectez-vous pour synchroniser.", + "chat_pathDeviceConfirmed": "Appareil confirmé.", + "chat_pathDeviceNotConfirmed": "L'appareil n'a pas encore été confirmé.", + "chat_type": "Saisir", + "chat_path": "Chemin", + "chat_publicKey": "Clé Publique", + "chat_compressOutgoingMessages": "Compresser les messages sortants", + "chat_floodForced": "Inondation (forcée)", + "chat_directForced": "Direct (forcé)", + "chat_hopsForced": "{count} sauts (forcés)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Inondation (auto)", + "chat_direct": "Afficher", + "chat_poiShared": "Point d'intérêt Partagé", + "chat_unread": "Non lu : {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Carte des nœuds", + "map_noNodesWithLocation": "Aucun nœud avec des données de localisation", + "map_nodesNeedGps": "Les nœuds doivent partager leurs coordonnées GPS\npour apparaître sur la carte.", + "map_nodesCount": "Nœuds : {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Epingles: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Chat", + "map_repeater": "Répétiteur", + "map_room": "Salle", + "map_sensor": "Capteur", + "map_pinDm": "Clé (DM)", + "map_pinPrivate": "Verrouiller (Privé)", + "map_pinPublic": "Clé (Public)", + "map_lastSeen": "Dernière fois vu", + "map_disconnectConfirm": "Êtes-vous sûr de vouloir vous déconnecter de cet appareil ?", + "map_from": "À partir de", + "map_source": "Source", + "map_flags": "Drapeaux", + "map_shareMarkerHere": "Partager le marqueur ici", + "map_pinLabel": "Étiquete de repin", + "map_label": "Étiquette", + "map_pointOfInterest": "Point d'intérêt", + "map_sendToContact": "Envoyer au contact", + "map_sendToChannel": "Envoyer sur le canal", + "map_noChannelsAvailable": "Aucun canal disponible", + "map_publicLocationShare": "Partager dans un lieu public", + "map_publicLocationShareConfirm": "Vous êtes sur le point de partager un emplacement dans {channelLabel}. Ce canal est public et toute personne disposant de la clé PSK peut le voir.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Connectez-vous à un appareil pour partager des marqueurs", + "map_filterNodes": "Filtrer les nœuds", + "map_nodeTypes": "Types de nœuds", + "map_chatNodes": "Nœuds de Chat", + "map_repeaters": "Répéteurs", + "map_otherNodes": "Autres nœuds", + "map_keyPrefix": "Préfixe clé", + "map_filterByKeyPrefix": "Filtrer par préfixe de clé", + "map_publicKeyPrefix": "Préfixe de clé publique", + "map_markers": "Marqueurs", + "map_showSharedMarkers": "Afficher les marqueurs partagés", + "map_lastSeenTime": "Dernière fois vu", + "map_sharedPin": "Clé partagée", + "map_joinRoom": "Rejoindre la salle", + "map_manageRepeater": "Gérer le répétiteur", + "mapCache_title": "Cache de Carte Hors Ligne", + "mapCache_selectAreaFirst": "Sélectionner une zone pour la mise en cache en premier", + "mapCache_noTilesToDownload": "Aucun tuilage à télécharger pour cette zone.", + "mapCache_downloadTilesTitle": "Télécharger les tuiles", + "mapCache_downloadTilesPrompt": "Télécharger {count} tuiles pour un usage hors ligne ?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Télécharger", + "mapCache_cachedTiles": "Cachez {count} tuiles", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Tiles mis en cache ({downloaded}) ({failed} ratés)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Vider le cache hors ligne", + "mapCache_clearOfflineCachePrompt": "Supprimer toutes les tuiles de carte mises en cache ?", + "mapCache_offlineCacheCleared": "Le cache hors ligne a été effacé.", + "mapCache_noAreaSelected": "Aucune zone sélectionnée", + "mapCache_cacheArea": "Zone de cache", + "mapCache_useCurrentView": "Utiliser la Vue Actuelle", + "mapCache_zoomRange": "Plage de zoom", + "mapCache_estimatedTiles": "Estimation des tuiles : {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Téléchargé {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Télécharger les tuiles", + "mapCache_clearCacheButton": "Vider le Cache", + "mapCache_failedDownloads": "Téléchargements échoués : {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Il y a tout juste maintenant", + "time_minutesAgo": "{minutes} minutes auparavant", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours}h auparavant", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} jours avant", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "heure", + "time_hours": "heures", + "time_day": "jour", + "time_days": "jours", + "time_week": "semaine", + "time_weeks": "semaines", + "time_month": "mois", + "time_months": "mois", + "time_minutes": "minutes", + "time_allTime": "Tout le temps", + "dialog_disconnect": "Déconnecter", + "dialog_disconnectConfirm": "Êtes-vous sûr de vouloir vous déconnecter de cet appareil ?", + "login_repeaterLogin": "Connexion au répétiteur", + "login_roomLogin": "Connexion Salle", + "login_password": "Mot de passe", + "login_enterPassword": "Entrez votre mot de passe", + "login_savePassword": "Sauvegarder le mot de passe", + "login_savePasswordSubtitle": "Le mot de passe sera stocké en toute sécurité sur cet appareil.", + "login_repeaterDescription": "Entrez le mot de passe du répétiteur pour accéder aux paramètres et à l'état.", + "login_roomDescription": "Entrez le mot de passe de la pièce pour accéder aux paramètres et à l'état.", + "login_routing": "Redirection", + "login_routingMode": "Mode de routage", + "login_autoUseSavedPath": "Auto (utiliser le chemin sauvegardé)", + "login_forceFloodMode": "Mode Inondation Forcée", + "login_managePaths": "Gérer les chemins", + "login_login": "Connexion", + "login_attempt": "Essayer {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Connexion échouée : {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Recharger", + "common_clear": "Effacer", + "path_currentPath": "Chemin actuel : {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Utiliser {count} {count, plural, =1{hop} other{hops}} chemin", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Entrer un chemin personnalisé", + "path_currentPathLabel": "Chemin actuel", + "path_hexPrefixInstructions": "Entrez les préfixes hexadécimaux de 2 caractères pour chaque saut, séparés par des virgules.", + "path_hexPrefixExample": "Exemple : A1,F2,3C (chaque nœud utilise le premier octet de sa clé publique).", + "path_labelHexPrefixes": "Préfixes hexadécimaux", + "path_helperMaxHops": "Max 64 sauts. Chaque préfixe fait 2 caractères hexadécimaux (1 octet)", + "path_selectFromContacts": "Sélectionner à partir des contacts :", + "path_noRepeatersFound": "Aucun répéteur ou serveur de salle n'a été trouvé.", + "path_customPathsRequire": "Les chemins personnalisés nécessitent des sauts intermédiaires qui peuvent transmettre des messages.", + "path_invalidHexPrefixes": "Préfixes hexadécimaux invalides : {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "Le chemin est trop long. Maximum 64 sauts autorisés.", + "path_setPath": "Définir le chemin", + "repeater_management": "Gestion des répétiteurs", + "repeater_managementTools": "Outils de Gestion", + "repeater_status": "État", + "repeater_statusSubtitle": "Afficher l'état, les statistiques et les voisins du répétiteur", + "repeater_telemetry": "Télémetrie", + "repeater_telemetrySubtitle": "Afficher la télémétrie des capteurs et les statistiques du système", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Envoyer des commandes au répétiteur", + "repeater_settings": "Paramètres", + "repeater_settingsSubtitle": "Configurer les paramètres du répétiteur", + "repeater_statusTitle": "État du répétiteur", + "repeater_routingMode": "Mode de routage", + "repeater_autoUseSavedPath": "Auto (utiliser le chemin sauvegardé)", + "repeater_forceFloodMode": "Mode de submersion forcée", + "repeater_pathManagement": "Gestion des chemins", + "repeater_refresh": "Rafraîchir", + "repeater_statusRequestTimeout": "Demande de statut délai dépassé.", + "repeater_errorLoadingStatus": "Erreur lors du chargement du statut : {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Informations Système", + "repeater_battery": "Batterie", + "repeater_clockAtLogin": "Horloge (au démarrage)", + "repeater_uptime": "Disponibilité", + "repeater_queueLength": "Longueur de la file d'attente", + "repeater_debugFlags": "Marqueurs de débogage", + "repeater_radioStatistics": "Statistiques Radio", + "repeater_lastRssi": "Dernier RSSI", + "repeater_lastSnr": "Dernier SNR", + "repeater_noiseFloor": "Niveau de Bruit", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Statistiques des paquets", + "repeater_sent": "Envoyé", + "repeater_received": "Reçu", + "repeater_duplicates": "Dupliques", + "repeater_daysHoursMinsSecs": "{days} jours {hours}h {minutes}m {seconds}s", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Total : {total}, Inondation : {flood}, Direct : {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Total : {total}, Inondation : {flood}, Direct : {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Inondation : {flood}, Direct : {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Total : {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Paramètres du répétiteur", + "repeater_basicSettings": "Paramètres de base", + "repeater_repeaterName": "Nom du répétiteur", + "repeater_repeaterNameHelper": "Afficher le nom de ce répétiteur", + "repeater_adminPassword": "Mot de passe Administrateur", + "repeater_adminPasswordHelper": "Mot de passe d'accès complet", + "repeater_guestPassword": "Mot de passe invité", + "repeater_guestPasswordHelper": "Accès en lecture seule avec mot de passe", + "repeater_radioSettings": "Paramètres Radio", + "repeater_frequencyMhz": "Fréquence (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Puissance", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Bande passante", + "repeater_spreadingFactor": "Facteur de répartition", + "repeater_codingRate": "Taux de codage", + "repeater_locationSettings": "Paramètres de localisation", + "repeater_latitude": "Latitude", + "repeater_latitudeHelper": "Degrés décimaux (par exemple, 37.7749)", + "repeater_longitude": "Longitude", + "repeater_longitudeHelper": "Degrés décimaux (par exemple, -122,4194)", + "repeater_features": "Fonctionnalités", + "repeater_packetForwarding": "Transfert de paquets", + "repeater_packetForwardingSubtitle": "Activer le répétiteur pour transmettre des paquets", + "repeater_guestAccess": "Accès Invité", + "repeater_guestAccessSubtitle": "Autoriser l'accès invité en lecture seule", + "repeater_privacyMode": "Mode de confidentialité", + "repeater_privacyModeSubtitle": "Cacher le nom/l'emplacement dans les publicités", + "repeater_advertisementSettings": "Paramètres de Publicité", + "repeater_localAdvertInterval": "Intervalle Publicité Locale", + "repeater_localAdvertIntervalMinutes": "{minutes} minutes", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Intervalle de Publicité Inondation", + "repeater_floodAdvertIntervalHours": "{hours} heures", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Intervalle publicitaire crypté", + "repeater_dangerZone": "Zone d'alerte", + "repeater_rebootRepeater": "Redémarrer Répéteur", + "repeater_rebootRepeaterSubtitle": "Réinitialiser l'appareil répétiteur", + "repeater_rebootRepeaterConfirm": "Êtes-vous sûr de vouloir redémarrer ce répétiteur ?", + "repeater_regenerateIdentityKey": "Ré générer la clé d'identité", + "repeater_regenerateIdentityKeySubtitle": "Générer une nouvelle paire de clés publique/privée", + "repeater_regenerateIdentityKeyConfirm": "Cela générera une nouvelle identité pour le répétiteur. Continuer ?", + "repeater_eraseFileSystem": "Supprimer le système de fichiers", + "repeater_eraseFileSystemSubtitle": "Formater le système de fichiers du répétiteur", + "repeater_eraseFileSystemConfirm": "AVERTISSEMENT : Cela effacera toutes les données du répétiteur. Cela ne peut pas être annulé !", + "repeater_eraseSerialOnly": "Erase n'est disponible que via la console série.", + "repeater_commandSent": "Commande envoyée : {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Erreur lors de l'envoi de la commande : {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "Confirmer", + "repeater_settingsSaved": "Les paramètres ont été enregistrés avec succès.", + "repeater_errorSavingSettings": "Erreur lors de la sauvegarde des paramètres : {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Rafraîchir les paramètres de base", + "repeater_refreshRadioSettings": "Rafraîchir les paramètres Radio", + "repeater_refreshTxPower": "Rafraîchir la tension TX", + "repeater_refreshLocationSettings": "Rafraîchir les paramètres de localisation", + "repeater_refreshPacketForwarding": "Rafraîchir le routage des paquets", + "repeater_refreshGuestAccess": "Rafraîchir l'accès invité", + "repeater_refreshPrivacyMode": "Rafraîchir le Mode Confidentialité", + "repeater_refreshAdvertisementSettings": "Rafraîchir les Paramètres de la Publicité", + "repeater_refreshed": "{label} rafraîchi", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Erreur lors du rafraîchissement de {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Répétiteur CLI", + "repeater_debugNextCommand": "Déboguer Prochaine Commande", + "repeater_commandHelp": "Aide", + "repeater_clearHistory": "Effacer l'historique", + "repeater_noCommandsSent": "Aucune commande n'a encore été envoyée.", + "repeater_typeCommandOrUseQuick": "Saisissez une commande ci-dessous ou utilisez les commandes rapides", + "repeater_enterCommandHint": "Entrer la commande...", + "repeater_previousCommand": "Commande précédente", + "repeater_nextCommand": "Prochaine commande", + "repeater_enterCommandFirst": "Entrez d'abord une commande", + "repeater_cliCommandFrameTitle": "Frame de commande CLI", + "repeater_cliCommandError": "Erreur : {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Obtenir le nom", + "repeater_cliQuickGetRadio": "Obtenir la Radio", + "repeater_cliQuickGetTx": "Obtenir TX", + "repeater_cliQuickNeighbors": "Voisins", + "repeater_cliQuickVersion": "Version", + "repeater_cliQuickAdvertise": "Publier", + "repeater_cliQuickClock": "Horloge", + "repeater_cliHelpAdvert": "Envoie un paquet publicitaire", + "repeater_cliHelpReboot": "Redémarre l'appareil. (Note, vous risquez d'obtenir 'Timeout' ce qui est normal)", + "repeater_cliHelpClock": "Affiche l'heure actuelle par l'horloge de chaque appareil.", + "repeater_cliHelpPassword": "Définit un nouveau mot de passe administrateur pour l'appareil.", + "repeater_cliHelpVersion": "Affiche la version du périphérique et la date de construction du micrologiciel.", + "repeater_cliHelpClearStats": "Réinitialise divers compteurs de statistiques à zéro.", + "repeater_cliHelpSetAf": "Définit le facteur de temps d'air.", + "repeater_cliHelpSetTx": "Définit la puissance de transmission LoRa en dBm (réinitialisation requise pour appliquer).", + "repeater_cliHelpSetRepeat": "Active ou désactive le rôle du répétiteur pour ce nœud.", + "repeater_cliHelpSetAllowReadOnly": "(Serveur de pièce) Si \"activé\", alors un mot de passe vide permettra la connexion, mais ne permettra pas de publier dans la pièce. (lecture seule uniquement)", + "repeater_cliHelpSetFloodMax": "Définit le nombre maximal de sauts pour les paquets de balayage entrants (si >= max, le paquet n'est pas acheminé).", + "repeater_cliHelpSetIntThresh": "Définit le seuil d'interférence (en dB). La valeur par défaut est de 14. Définir sur 0 désactive la détection des interférences de canal.", + "repeater_cliHelpSetAgcResetInterval": "Définit l'intervalle pour réinitialiser le contrôleur de gain automatique. Mettez à 0 pour désactiver.", + "repeater_cliHelpSetMultiAcks": "Active ou désactive la fonctionnalité « double ACKs ».", + "repeater_cliHelpSetAdvertInterval": "Définit l'intervalle du minuteur pour envoyer un paquet d'annonce local (sans relais). Définir sur 0 pour désactiver.", + "repeater_cliHelpSetFloodAdvertInterval": "Définit l'intervalle du minuteur en heures pour envoyer un paquet d'annonce massive. Définir sur 0 pour désactiver.", + "repeater_cliHelpSetGuestPassword": "Définit/met à jour le mot de passe de l'invité. (pour les répéteurs, les connexions d'invités peuvent envoyer la requête \"Get Stats\")", + "repeater_cliHelpSetName": "Définit le nom de la publicité.", + "repeater_cliHelpSetLat": "Définit la latitude de la carte des annonces. (degrés décimaux)", + "repeater_cliHelpSetLon": "Définit la longitude de la carte de l'annonce. (degrés décimaux)", + "repeater_cliHelpSetRadio": "Définit complètement de nouveaux paramètres de radio et les enregistre dans les préférences. Nécessite une commande \"redémarrage\" pour les appliquer.", + "repeater_cliHelpSetRxDelay": "Paramètres (expérimental) de base pour appliquer un léger délai aux paquets reçus, en fonction de la force du signal/score. Définir sur 0 pour désactiver.", + "repeater_cliHelpSetTxDelay": "Définit un facteur multiplié par le temps de fonctionnement en mode inondation pour un paquet et avec un système de slot aléatoire, afin de retarder son envoi (pour diminuer la probabilité de collisions).", + "repeater_cliHelpSetDirectTxDelay": "Identique à txdelay, mais pour appliquer un délai aléatoire au transfert des paquets en mode direct.", + "repeater_cliHelpSetBridgeEnabled": "Activer/Désactiver le pont.", + "repeater_cliHelpSetBridgeDelay": "Définir le délai avant de renvoyer les paquets.", + "repeater_cliHelpSetBridgeSource": "Choisissez si le pont retransmettra les paquets reçus ou les paquets transmis.", + "repeater_cliHelpSetBridgeBaud": "Définir la vitesse de communication série pour les ponts Rs232.", + "repeater_cliHelpSetBridgeSecret": "Définir le secret du pont pour les ponts espnow.", + "repeater_cliHelpSetAdcMultiplier": "Définit un facteur personnalisé pour ajuster la tension de la batterie signalée (uniquement pris en charge sur certains cartes).", + "repeater_cliHelpTempRadio": "Définit des paramètres radio temporaires pour le nombre de minutes donné, puis revient aux paramètres radio d'origine. (ne sauvegarde pas dans les préférences).", + "repeater_cliHelpSetPerm": "Modifie l’ACL. Supprime l’entrée correspondante (par préfixe de clé publique) si \"permissions\" est égal à zéro. Ajoute une nouvelle entrée si la clé publique hexadécimale a une longueur complète et n’est pas actuellement dans l’ACL. Met à jour l’entrée en fonction du préfixe de clé publique. Les bits de permission varient en fonction du rôle du firmware, mais les 2 bits inférieurs sont : 0 (Invité), 1 (Lecture seule), 2 (Lecture/écriture), 3 (Administrateur).", + "repeater_cliHelpGetBridgeType": "Obtenir le type de pont : aucun, rs232, espnow", + "repeater_cliHelpLogStart": "Démarre l'enregistrement des paquets dans le système de fichiers.", + "repeater_cliHelpLogStop": "Arrêter de journaliser les paquets vers le système de fichiers.", + "repeater_cliHelpLogErase": "Supprime les journaux de paquets du système de fichiers.", + "repeater_cliHelpNeighbors": "Affiche une liste d'autres nœuds répétiteurs entendus via des publicités sans relais. Chaque ligne est id-préfixe-hexadécimal:timestamp:snr-fois-4", + "repeater_cliHelpNeighborRemove": "Supprime la première entrée correspondante (par préfixe de clé publique (hexadécimal)) de la liste des voisins.", + "repeater_cliHelpRegion": "(série uniquement) Liste toutes les régions définies et les autorisations de débordement actuelles.", + "repeater_cliHelpRegionLoad": "REMARQUE : il s'agit d'une invocation multi-commande spéciale. Chaque commande subséquente est un nom de région (indenté avec des espaces pour indiquer la hiérarchie parent, avec un minimum d'un espace). Terminé par l'envoi d'une ligne vide/commande.", + "repeater_cliHelpRegionGet": "Recherche la région avec le préfixe de nom donné (ou \"\" pour l'étendue globale). Répond avec \"-> nom-de-région (nom-parent) 'F'\"", + "repeater_cliHelpRegionPut": "Ajoute ou met à jour une définition de région avec le nom donné.", + "repeater_cliHelpRegionRemove": "Supprime une définition de région avec le nom donné.", + "repeater_cliHelpRegionAllowf": "Définit les autorisations de \"Flot\" pour la région donnée. ('' pour la portée globale/héritée)", + "repeater_cliHelpRegionDenyf": "Supprime l'autorisation 'F'lood' pour la région donnée. (NOTE : à ce stade, il n'est pas conseillé de l'utiliser sur l'étendue globale/héritée !! )", + "repeater_cliHelpRegionHome": "Répond avec la région 'maison' actuelle. (Note appliquée nulle part pour l'instant, réservée à une utilisation future)", + "repeater_cliHelpRegionHomeSet": "Définit la région 'maison'.", + "repeater_cliHelpRegionSave": "Conserve la liste/la carte des régions dans le stockage.", + "repeater_cliHelpGps": "Affiche l’état du GPS. Lorsque le GPS est éteint, il répond uniquement « éteint », si allumé, il répond avec « allumé », l’état, la correction, le nombre de satellites.", + "repeater_cliHelpGpsOnOff": "Activer/désactiver le GPS.", + "repeater_cliHelpGpsSync": "Synchronise l'heure du nœud avec l'horloge GPS.", + "repeater_cliHelpGpsSetLoc": "Définit la position du nœud aux coordonnées GPS et enregistre les préférences.", + "repeater_cliHelpGpsAdvert": "Donne la configuration de l'annonce de la localisation du nœud :\n- none : ne pas inclure la localisation dans les annonces\n- share : partager la localisation GPS (du SensorManager)\n- prefs : annoncer la localisation stockée dans les préférences", + "repeater_cliHelpGpsAdvertSet": "Définit la configuration de l'annonce de localisation.", + "repeater_commandsListTitle": "Liste des commandes", + "repeater_commandsListNote": "NOTE : pour les diverses commandes « set »..., il existe également une commande « get »...", + "repeater_general": "Général", + "repeater_settingsCategory": "Paramètres", + "repeater_bridge": "Pont", + "repeater_logging": "Journalisation", + "repeater_neighborsRepeaterOnly": "Voisins (Uniquement répétiteur)", + "repeater_regionManagementRepeaterOnly": "Gestion des régions (uniquement pour le répétiteur)", + "repeater_regionNote": "Les commandes de région ont été introduites pour gérer les définitions et les autorisations des régions.", + "repeater_gpsManagement": "Gestion GPS", + "repeater_gpsNote": "La commande GPS a été introduite pour gérer les sujets liés à la localisation.", + "telemetry_receivedData": "Données de télémétrie reçues", + "telemetry_requestTimeout": "Demande de télémétrie expirée.", + "telemetry_errorLoading": "Erreur lors du chargement de la télémétrie : {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "Aucune donnée de télémétrie disponible.", + "telemetry_channelTitle": "Canal {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Batterie", + "telemetry_voltageLabel": "Tension", + "telemetry_mcuTemperatureLabel": "Température du MCU", + "telemetry_temperatureLabel": "Température", + "telemetry_currentLabel": "Actuellement", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Chemin de paquet", + "channelPath_viewMap": "Afficher la carte", + "channelPath_otherObservedPaths": "Autres chemins observés", + "channelPath_repeaterHops": "Sauts du répétiteur", + "channelPath_noHopDetails": "Les détails de l'envoi ne sont pas fournis pour ce paquet.", + "channelPath_messageDetails": "Détails du message", + "channelPath_senderLabel": "Expéditeur", + "channelPath_timeLabel": "Temps", + "channelPath_repeatsLabel": "Répétitions", + "channelPath_pathLabel": "Chemin {index}", + "channelPath_observedLabel": "Observé", + "channelPath_observedPathTitle": "Chemin observé {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "Aucune donnée de localisation", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Inconnu", + "channelPath_floodPath": "Inondation", + "channelPath_directPath": "Afficher", + "channelPath_observedZeroOf": "0 de {total} sauts", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} sur {total} sauts", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Carte du chemin", + "channelPath_noRepeaterLocations": "Aucune position de répétiteur disponible pour ce chemin.", + "channelPath_primaryPath": "Chemin {index} (Principal)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Chemin", + "channelPath_observedPathHeader": "Chemin observé", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "Aucun détail de saut disponible pour ce paquet.", + "channelPath_unknownRepeater": "Répéteur Inconnu", + "listFilter_tooltip": "Filtrer et trier", + "listFilter_sortBy": "Trier par", + "listFilter_latestMessages": "Dernières messages", + "listFilter_heardRecently": "Écoute récemment", + "listFilter_az": "A à Z", + "listFilter_filters": "Filtres", + "listFilter_all": "Tout", + "listFilter_users": "Utilisateurs", + "listFilter_repeaters": "Répéteurs", + "listFilter_roomServers": "Serveurs de pièce", + "listFilter_unreadOnly": "Messages non lus seulement", + "listFilter_newGroup": "Nouvelle groupe" +} diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb new file mode 100644 index 0000000..72be091 --- /dev/null +++ b/lib/l10n/app_it.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "it", + "appTitle": "MeshCore Open", + "nav_contacts": "Contatti", + "nav_channels": "Canali", + "nav_map": "Mappa", + "common_cancel": "Annulla", + "common_connect": "Connetti", + "common_unknownDevice": "Dispositivo sconosciuto", + "common_save": "Salva", + "common_delete": "Elimina", + "common_close": "Chiudi", + "common_edit": "Modifica", + "common_add": "Aggiungi", + "common_settings": "Impostazioni", + "common_disconnect": "Disconnetti", + "common_connected": "Connesso", + "common_disconnected": "Disconnesso", + "common_create": "Crea", + "common_continue": "Continua", + "common_share": "Condividi", + "common_copy": "Copia", + "common_retry": "Riprova", + "common_hide": "Nascondi", + "common_remove": "Elimina", + "common_enable": "Abilita", + "common_disable": "Disattivare", + "common_reboot": "Riavvia", + "common_loading": "Caricamento...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Scansione in corso per i dispositivi...", + "scanner_connecting": "Connessione...", + "scanner_disconnecting": "Disconnessione...", + "scanner_notConnected": "Non connesso", + "scanner_connectedTo": "Connesso a {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Ricerca dispositivi MeshCore...", + "scanner_tapToScan": "Tocca Scansiona per trovare i dispositivi MeshCore", + "scanner_connectionFailed": "Connessione fallita: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Interrompere", + "scanner_scan": "Scansiona", + "device_quickSwitch": "Passa velocemente", + "device_meshcore": "MeshCore", + "settings_title": "Impostazioni", + "settings_deviceInfo": "Informazioni Dispositivo", + "settings_appSettings": "Impostazioni App", + "settings_appSettingsSubtitle": "Notifiche, messaggi e preferenze della mappa", + "settings_nodeSettings": "Impostazioni Nodo", + "settings_nodeName": "Nome Nodo", + "settings_nodeNameNotSet": "Non impostato", + "settings_nodeNameHint": "Inserisci nome nodo", + "settings_nodeNameUpdated": "Nome aggiornato", + "settings_radioSettings": "Impostazioni Radio", + "settings_radioSettingsSubtitle": "Frequenza, potenza, fattore di dispersione", + "settings_radioSettingsUpdated": "Impostazioni radio aggiornate", + "settings_location": "Posizione", + "settings_locationSubtitle": "coordinate GPS", + "settings_locationUpdated": "Posizione aggiornata", + "settings_locationBothRequired": "Inserire sia la latitudine che la longitudine.", + "settings_locationInvalid": "Latitudine o longitudine non valida.", + "settings_latitude": "Latitudine", + "settings_longitude": "Longitudine", + "settings_privacyMode": "Modalità Privacy", + "settings_privacyModeSubtitle": "Nascondere nome/luogo negli annunci", + "settings_privacyModeToggle": "Attiva la modalità privacy per nascondere il tuo nome e la tua posizione negli annunci.", + "settings_privacyModeEnabled": "Modalità privacy abilitata", + "settings_privacyModeDisabled": "Modalità privacy disabilitata", + "settings_actions": "Azioni", + "settings_sendAdvertisement": "Invia Annuncio", + "settings_sendAdvertisementSubtitle": "Presenza trasmessa ora", + "settings_advertisementSent": "Annuncio inviato", + "settings_syncTime": "Tempo di sincronizzazione", + "settings_syncTimeSubtitle": "Imposta l'orologio del dispositivo sull'ora del telefono", + "settings_timeSynchronized": "Sincronizzato nel tempo", + "settings_refreshContacts": "Aggiorna Contatti", + "settings_refreshContactsSubtitle": "Ricaricare l'elenco dei contatti dal dispositivo", + "settings_rebootDevice": "Riavvia Dispositivo", + "settings_rebootDeviceSubtitle": "Riavviare il dispositivo MeshCore", + "settings_rebootDeviceConfirm": "Sei sicuro di voler riavviare il dispositivo? Sarai disconnesso.", + "settings_debug": "Risoluzione dei problemi", + "settings_bleDebugLog": "Log di Debug BLE", + "settings_bleDebugLogSubtitle": "Comandi, risposte e dati grezzi BLE", + "settings_appDebugLog": "Log di Debug dell'App", + "settings_appDebugLogSubtitle": "Messaggi di debug dell'applicazione", + "settings_about": "Informazioni", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "Progetto Open Source MeshCore 2024", + "settings_aboutDescription": "Un client Flutter open-source per i dispositivi di rete mesh LoRa Core di MeshCore.", + "settings_infoName": "Nome", + "settings_infoId": "ID", + "settings_infoStatus": "Stato", + "settings_infoBattery": "Batteria", + "settings_infoPublicKey": "Chiave Pubblica", + "settings_infoContactsCount": "Numero contatti", + "settings_infoChannelCount": "Numero Canale", + "settings_presets": "Preset", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Frequenza (MHz)", + "settings_frequencyHelper": "300,0 - 2500,0", + "settings_frequencyInvalid": "Frequenza non valida (300-2500 MHz)", + "settings_bandwidth": "Larghezza di banda", + "settings_spreadingFactor": "Fattore di Spettro", + "settings_codingRate": "Tasso di Codifica", + "settings_txPower": "TX Potenza (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Potere TX non valido (0-22 dBm)", + "settings_longRange": "Lungo Raggio", + "settings_fastSpeed": "Velocità Rapida", + "settings_error": "Errore: {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "Impostazioni App", + "appSettings_appearance": "Aspetto", + "appSettings_theme": "Tema", + "appSettings_themeSystem": "Impostazione predefinita del sistema", + "appSettings_themeLight": "Luce", + "appSettings_themeDark": "Scuro", + "appSettings_language": "Lingua", + "appSettings_languageSystem": "Predefinito di sistema", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Notifiche", + "appSettings_enableNotifications": "Abilita Notifiche", + "appSettings_enableNotificationsSubtitle": "Ricevi notifiche per messaggi e annunci", + "appSettings_notificationPermissionDenied": "Permesso di notifica negato", + "appSettings_notificationsEnabled": "Notifiche abilitate", + "appSettings_notificationsDisabled": "Notifiche disattivate", + "appSettings_messageNotifications": "Notifiche Messaggi", + "appSettings_messageNotificationsSubtitle": "Mostra notifica all'arrivo di nuovi messaggi", + "appSettings_channelMessageNotifications": "Notifiche Messaggi Canale", + "appSettings_channelMessageNotificationsSubtitle": "Mostra notifica all'arrivo di messaggi nel canale", + "appSettings_advertisementNotifications": "Notifiche Pubblicitarie", + "appSettings_advertisementNotificationsSubtitle": "Mostra notifica quando vengono scoperti nuovi nodi", + "appSettings_messaging": "Messaggi", + "appSettings_clearPathOnMaxRetry": "Cancella Percorso su Massimo Riprovo", + "appSettings_clearPathOnMaxRetrySubtitle": "Reimposta il percorso di contatto dopo 5 tentativi di invio falliti", + "appSettings_pathsWillBeCleared": "I percorsi verranno puliti dopo 5 tentativi falliti.", + "appSettings_pathsWillNotBeCleared": "I percorsi non verranno eliminati automaticamente.", + "appSettings_autoRouteRotation": "Rotazione Percorso Automatico", + "appSettings_autoRouteRotationSubtitle": "Alterna tra i percorsi migliori e la modalità alluvione", + "appSettings_autoRouteRotationEnabled": "Rotazione percorso automatico abilitata", + "appSettings_autoRouteRotationDisabled": "Rotazione del percorso automatico disabilitata", + "appSettings_battery": "Batteria", + "appSettings_batteryChemistry": "Chimica della batteria", + "appSettings_batteryChemistryPerDevice": "Impostazione per dispositivo ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Connetti a un dispositivo per scegliere", + "appSettings_batteryNmc": "18650 NMC (3,0-4,2V)", + "appSettings_batteryLifepo4": "LiFePO4 (2,6-3,65V)", + "appSettings_batteryLipo": "LiPo (3,0-4,2V)", + "appSettings_mapDisplay": "Visualizzazione Mappa", + "appSettings_showRepeaters": "Mostra Ripetitori", + "appSettings_showRepeatersSubtitle": "Mostra i nodi ripetitori sulla mappa", + "appSettings_showChatNodes": "Mostra Nodi Chat", + "appSettings_showChatNodesSubtitle": "Mostra i nodi di chat sulla mappa", + "appSettings_showOtherNodes": "Mostra altri nodi", + "appSettings_showOtherNodesSubtitle": "Mostra altri tipi di nodo sulla mappa", + "appSettings_timeFilter": "Filtro Temporale", + "appSettings_timeFilterShowAll": "Mostra tutti i nodi", + "appSettings_timeFilterShowLast": "Mostra i nodi delle ultime {hours} ore", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Filtro Tempo Mappa", + "appSettings_showNodesDiscoveredWithin": "Mostra i nodi scoperti all'interno di:", + "appSettings_allTime": "Tutto il tempo", + "appSettings_lastHour": "Ultima ora", + "appSettings_last6Hours": "Ultimi 6 ore", + "appSettings_last24Hours": "Ultime 24 ore", + "appSettings_lastWeek": "La settimana scorsa", + "appSettings_offlineMapCache": "Cache Mappa Offline", + "appSettings_noAreaSelected": "Nessun'area selezionata", + "appSettings_areaSelectedZoom": "Area selezionata (zoom {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Risoluzione dei problemi", + "appSettings_appDebugLogging": "Registrazione Debug App", + "appSettings_appDebugLoggingSubtitle": "Messaggi di debug dell'app Log per la risoluzione dei problemi", + "appSettings_appDebugLoggingEnabled": "Logging di debug dell'app abilitato", + "appSettings_appDebugLoggingDisabled": "Logging del debug dell'app disabilitato", + "contacts_title": "Contatti", + "contacts_noContacts": "Nessun contatto ancora", + "contacts_contactsWillAppear": "I contatti appariranno quando i dispositivi pubblicizzano.", + "contacts_searchContacts": "Cerca contatti...", + "contacts_noUnreadContacts": "Nessun contatto non letto", + "contacts_noContactsFound": "Nessun contatto o gruppo trovato.", + "contacts_deleteContact": "Elimina Contatto", + "contacts_removeConfirm": "Eliminare {contactName} dai contatti?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Gestisci Ripetitore", + "contacts_roomLogin": "Login Camera", + "contacts_openChat": "Apri Chat", + "contacts_editGroup": "Modifica Gruppo", + "contacts_deleteGroup": "Elimina Gruppo", + "contacts_deleteGroupConfirm": "Eliminare \"{groupName}\"?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Nuovo Gruppo", + "contacts_groupName": "Nome gruppo", + "contacts_groupNameRequired": "Il nome del gruppo è obbligatorio.", + "contacts_groupAlreadyExists": "Il gruppo \"{name}\" esiste già.", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Filtra i contatti...", + "contacts_noContactsMatchFilter": "Nessun contatto corrisponde al tuo filtro", + "contacts_noMembers": "Nessun membro", + "contacts_lastSeenNow": "Ultimo avvistamento ora", + "contacts_lastSeenMinsAgo": "Ultimo visto {minutes} minuti fa", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Ultimo visto 1 ora fa", + "contacts_lastSeenHoursAgo": "Ultimo visto {hours} ore fa", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Ultimo visto 1 giorno fa", + "contacts_lastSeenDaysAgo": "Ultimo visto {days} giorni fa", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Canali", + "channels_noChannelsConfigured": "Nessun canale configurato", + "channels_addPublicChannel": "Aggiungi Canale Pubblico", + "channels_searchChannels": "Cerca canali...", + "channels_noChannelsFound": "Nessun canale trovato", + "channels_channelIndex": "Canale {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Canale hashtag", + "channels_public": "Pubblico", + "channels_private": "Privato", + "channels_publicChannel": "Canale pubblico", + "channels_privateChannel": "Canale privato", + "channels_editChannel": "Modifica canale", + "channels_deleteChannel": "Elimina canale", + "channels_deleteChannelConfirm": "Eliminare \"{name}\"? Non può essere annullato.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Canale \"{name}\" eliminato", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Aggiungi Canale", + "channels_channelIndexLabel": "Indice Canale", + "channels_channelName": "Nome canale", + "channels_usePublicChannel": "Utilizza il canale pubblico", + "channels_standardPublicPsk": "PSK pubblico standard", + "channels_pskHex": "PSK (Hex)", + "channels_generateRandomPsk": "Genera una chiave di permutazione casuale", + "channels_enterChannelName": "Inserisci un nome per il canale", + "channels_pskMustBe32Hex": "PSK deve essere composto da 32 caratteri esadecimali.", + "channels_channelAdded": "Canale \"{name}\" aggiunto", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Modifica Canale {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "Compressione SMAZ", + "channels_channelUpdated": "Canale \"{name}\" aggiornato", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "Canale pubblico aggiunto", + "channels_sortBy": "Ordina per", + "channels_sortManual": "Manuale", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "Ultimi messaggi", + "channels_sortUnread": "Non letto", + "chat_noMessages": "Nessun messaggio ancora", + "chat_sendMessageToStart": "Invia un messaggio per iniziare", + "chat_originalMessageNotFound": "Messaggio originale non trovato", + "chat_replyingTo": "Rispondere a {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Rispondi a {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Posizione", + "chat_sendMessageTo": "Invia un messaggio a {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Digita un messaggio...", + "chat_messageTooLong": "Messaggio troppo lungo (massimo {maxBytes} byte).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Messaggio copiato", + "chat_messageDeleted": "Messaggio eliminato", + "chat_retryingMessage": "Riprovo", + "chat_retryCount": "Riprova {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "Invia GIF", + "chat_reply": "Rispondi", + "chat_addReaction": "Aggiungi Reazione", + "chat_me": "Me", + "emojiCategorySmileys": "Emoji", + "emojiCategoryGestures": "Gesti", + "emojiCategoryHearts": "Cuori", + "emojiCategoryObjects": "Oggetti", + "gifPicker_title": "Scegli un GIF", + "gifPicker_searchHint": "Cerca GIF...", + "gifPicker_poweredBy": "Potenziato da GIPHY", + "gifPicker_noGifsFound": "Nessun GIF trovato", + "gifPicker_failedLoad": "Impossibile caricare i GIF", + "gifPicker_failedSearch": "Impossibile trovare GIF", + "gifPicker_noInternet": "Nessuna connessione internet", + "debugLog_appTitle": "Log di Debug dell'App", + "debugLog_bleTitle": "Log di Debug BLE", + "debugLog_copyLog": "Copia log", + "debugLog_clearLog": "Cancella log", + "debugLog_copied": "Log di debug copiato", + "debugLog_bleCopied": "Log BLE copiato", + "debugLog_noEntries": "Non ci sono ancora log di debug.", + "debugLog_enableInSettings": "Abilita il logging di debug dell'app nelle impostazioni", + "debugLog_frames": "Frame", + "debugLog_rawLogRx": "Log Raw-RX", + "debugLog_noBleActivity": "Nessuna attività BLE rilevata ancora.", + "debugFrame_length": "Lunghezza del Frame: {count} byte", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Comando: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Messaggio di testo:", + "debugFrame_destinationPubKey": "- Destinazione PubChiave: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Timestamp: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Flag: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "Tipo di testo: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Semplice", + "debugFrame_text": "- Testo: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Dumpa Esadecimale:", + "chat_pathManagement": "Gestione Percorsi", + "chat_routingMode": "Modalità di routing", + "chat_autoUseSavedPath": "Utilizza il percorso salvato", + "chat_forceFloodMode": "Modalità Inondamento Forzato", + "chat_recentAckPaths": "Percorsi ACK Recenti (tocca per usare):", + "chat_pathHistoryFull": "La cronologia del percorso è piena. Rimuovi gli elementi per aggiungere nuovi.", + "chat_hopSingular": "salta", + "chat_hopPlural": "salta", + "chat_hopsCount": "{count} {count, plural, =1{salto} other{salti}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "successi", + "chat_removePath": "Rimuovi percorso", + "chat_noPathHistoryYet": "Non c'è ancora una cronologia del percorso.\nInvia un messaggio per scoprire i percorsi.", + "chat_pathActions": "Azioni Percorso:", + "chat_setCustomPath": "Imposta Percorso Personalizzato", + "chat_setCustomPathSubtitle": "Specifica manualmente il percorso di routing", + "chat_clearPath": "Cancella Percorso", + "chat_clearPathSubtitle": "Riprova la scoperta alla prossima invio", + "chat_pathCleared": "Percorso sgomberato. Il prossimo messaggio riidentifierà il percorso.", + "chat_floodModeSubtitle": "Utilizza l'interruttore di routing nella barra delle applicazioni", + "chat_floodModeEnabled": "Modalità alluvione abilitata. Disattivala tramite l'icona di routing nella barra in alto.", + "chat_fullPath": "Percorso Completo", + "chat_pathDetailsNotAvailable": "I dettagli del percorso non sono ancora disponibili. Prova a inviare un messaggio per ricaricare.", + "chat_pathSetHops": "Percorso impostato: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Salvatato localmente. Connetti per sincronizzare.", + "chat_pathDeviceConfirmed": "Dispositivo confermato.", + "chat_pathDeviceNotConfirmed": "Dispositivo non confermato ancora.", + "chat_type": "Digita", + "chat_path": "Percorso", + "chat_publicKey": "Chiave Pubblica", + "chat_compressOutgoingMessages": "Comprimi messaggi in uscita", + "chat_floodForced": "Inondazione (forzata)", + "chat_directForced": "Riavvia (forzato)", + "chat_hopsForced": "{count} salti (forzati)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Inondazione (auto)", + "chat_direct": "Salva", + "chat_poiShared": "Punti di Interesse Condivisi", + "chat_unread": "Non letti: {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Mappa Nodi", + "map_noNodesWithLocation": "Nessun nodo con dati di posizione", + "map_nodesNeedGps": "I nodi devono condividere le loro coordinate GPS\nper apparire sulla mappa", + "map_nodesCount": "Nodi: {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Puntatori: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Chat", + "map_repeater": "Ripetitore", + "map_room": "Stanza", + "map_sensor": "Sensore", + "map_pinDm": "Codice PIN (DM)", + "map_pinPrivate": "Blocco (Privato)", + "map_pinPublic": "Pin (Pubblico)", + "map_lastSeen": "Ultimo visto", + "map_disconnectConfirm": "Sei sicuro di voler disconnetterti da questo dispositivo?", + "map_from": "Da", + "map_source": "Fonte", + "map_flags": "Bandiere", + "map_shareMarkerHere": "Condividi marcatore qui", + "map_pinLabel": "Etichetta PIN", + "map_label": "Etichetta", + "map_pointOfInterest": "Punto di interesse", + "map_sendToContact": "Invia a contatto", + "map_sendToChannel": "Invia al canale", + "map_noChannelsAvailable": "Nessun canale disponibile", + "map_publicLocationShare": "Condividi in una posizione pubblica", + "map_publicLocationShareConfirm": "Stai per condividere una posizione in {channelLabel}. Questo canale è pubblico e chiunque abbia la PSK può vederlo.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Connetti a un dispositivo per condividere i segnaposti", + "map_filterNodes": "Filtra Nodi", + "map_nodeTypes": "Tipi di Nodo", + "map_chatNodes": "Nodi di Chat", + "map_repeaters": "Ripetitori", + "map_otherNodes": "Altri Nodi", + "map_keyPrefix": "Prefisso Chiave", + "map_filterByKeyPrefix": "Filtra per prefisso chiave", + "map_publicKeyPrefix": "Prefisso chiave pubblica", + "map_markers": "Segnaposto", + "map_showSharedMarkers": "Mostra i segnaposto condivisi", + "map_lastSeenTime": "Ultimo Tempo di Visualizzazione", + "map_sharedPin": "Condividi PIN", + "map_joinRoom": "Unisciti alla stanza", + "map_manageRepeater": "Gestisci Ripetitore", + "mapCache_title": "Cache Mappa Offline", + "mapCache_selectAreaFirst": "Seleziona un'area da memorizzare nella cache per prima.", + "mapCache_noTilesToDownload": "Nessun tile da scaricare per questa area", + "mapCache_downloadTilesTitle": "Scarica mattoncini", + "mapCache_downloadTilesPrompt": "Scarica {count} tile per l'uso offline?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Scarica", + "mapCache_cachedTiles": "Cacheggiate {count} tile", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Tile memorizzati {downloaded} ({failed} falliti)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Cancella cache offline", + "mapCache_clearOfflineCachePrompt": "Eliminare tutte le tile di mappa memorizzate nella cache?", + "mapCache_offlineCacheCleared": "Cache offline eliminata", + "mapCache_noAreaSelected": "Nessun'area selezionata", + "mapCache_cacheArea": "Area Cache", + "mapCache_useCurrentView": "Utilizza la visualizzazione corrente", + "mapCache_zoomRange": "Intervallo Zoom", + "mapCache_estimatedTiles": "Stima dei mattoni: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Scaricati {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Scarica Tessere", + "mapCache_clearCacheButton": "Svuota Cache", + "mapCache_failedDownloads": "Download falliti: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Proprio ora", + "time_minutesAgo": "{minutes} minuti fa", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours}h fa", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} giorni fa", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "ora", + "time_hours": "ore", + "time_day": "giorno", + "time_days": "giorni", + "time_week": "settimana", + "time_weeks": "settimane", + "time_month": "mese", + "time_months": "mesi", + "time_minutes": "minuti", + "time_allTime": "Tutto il Tempo", + "dialog_disconnect": "Disconnetti", + "dialog_disconnectConfirm": "Sei sicuro di voler disconnetterti da questo dispositivo?", + "login_repeaterLogin": "Login Ripetitore", + "login_roomLogin": "Login Camera", + "login_password": "Password", + "login_enterPassword": "Inserisci password", + "login_savePassword": "Salva password", + "login_savePasswordSubtitle": "La password verrà memorizzata in modo sicuro su questo dispositivo.", + "login_repeaterDescription": "Inserisci la password del ripetitore per accedere alle impostazioni e allo stato.", + "login_roomDescription": "Inserisci la password della stanza per accedere alle impostazioni e allo stato.", + "login_routing": "Instradamento", + "login_routingMode": "Modalità di routing", + "login_autoUseSavedPath": "Utilizza il percorso salvato", + "login_forceFloodMode": "Modalità Inondamento Forzato", + "login_managePaths": "Gestisci Percorsi", + "login_login": "Accedi", + "login_attempt": "Prova {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Accesso fallito: {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Ricaricare", + "common_clear": "Cancella", + "path_currentPath": "Percorso corrente: {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Utilizzare {count} {count, plural, =1{hop} other{hops}} percorso", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Inserisci percorso personalizzato", + "path_currentPathLabel": "Percorso corrente", + "path_hexPrefixInstructions": "Inserire i prefissi esadecimali a 2 caratteri per ogni salto, separati da virgole.", + "path_hexPrefixExample": "Esempio: A1,F2,3C (ogni nodo utilizza il primo byte della sua chiave pubblica)", + "path_labelHexPrefixes": "Prefisso esadecimale (percorso)", + "path_helperMaxHops": "Massimo 64 salti. Ogni prefisso è composto da 2 caratteri esadecimali (1 byte)", + "path_selectFromContacts": "Seleziona da contatti:", + "path_noRepeatersFound": "Non sono stati trovati ripetitori o server di stanza.", + "path_customPathsRequire": "I percorsi personalizzati richiedono salti intermedi che possono inoltrare messaggi.", + "path_invalidHexPrefixes": "Prefissi esadecimali non validi: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "Il percorso è troppo lungo. Massimo 64 salti consentiti.", + "path_setPath": "Imposta Percorso", + "repeater_management": "Gestione Ripetitori", + "repeater_managementTools": "Strumenti di Gestione", + "repeater_status": "Stato", + "repeater_statusSubtitle": "Visualizza lo stato, le statistiche e i vicini del ripetitore", + "repeater_telemetry": "Telemetry", + "repeater_telemetrySubtitle": "Visualizza i dati di telemetria dei sensori e le statistiche di sistema", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Invia comandi al ripetitore", + "repeater_settings": "Impostazioni", + "repeater_settingsSubtitle": "Configura i parametri del ripetitore", + "repeater_statusTitle": "Stato del Ripetitore", + "repeater_routingMode": "Modalità di routing", + "repeater_autoUseSavedPath": "Percorso salvato automatico", + "repeater_forceFloodMode": "Modalità Inondamento Forzato", + "repeater_pathManagement": "Gestione dei percorsi", + "repeater_refresh": "Aggiorna", + "repeater_statusRequestTimeout": "Richiesta stato scaduta.", + "repeater_errorLoadingStatus": "Errore nel caricamento dello stato: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Informazioni di sistema", + "repeater_battery": "Batteria", + "repeater_clockAtLogin": "Orologio (all'accesso)", + "repeater_uptime": "Disponibilità", + "repeater_queueLength": "Lunghezza della coda", + "repeater_debugFlags": "Impostazioni Debug", + "repeater_radioStatistics": "Statistiche Radio", + "repeater_lastRssi": "Ultimo RSSI", + "repeater_lastSnr": "Ultimo SNR", + "repeater_noiseFloor": "Livello del Rumore", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Statistiche del Pacchetto", + "repeater_sent": "Inviato", + "repeater_received": "Ricevuto", + "repeater_duplicates": "Duplicati", + "repeater_daysHoursMinsSecs": "{days} giorni {hours}h {minutes}m {seconds}s", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Totale: {total}, Inondazione: {flood}, Diretto: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Totale: {total}, Inondazione: {flood}, Diretto: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Inondazione: {flood}, Diretto: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Totale: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Impostazioni Ripetitore", + "repeater_basicSettings": "Impostazioni di Base", + "repeater_repeaterName": "Nome Ripetitore", + "repeater_repeaterNameHelper": "Visualizza il nome di questo ripetitore", + "repeater_adminPassword": "Password Amministratore", + "repeater_adminPasswordHelper": "Accesso completo password", + "repeater_guestPassword": "Password Ospite", + "repeater_guestPasswordHelper": "Accesso in sola lettura con password", + "repeater_radioSettings": "Impostazioni Radio", + "repeater_frequencyMhz": "Frequenza (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Potenza", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Larghezza di banda", + "repeater_spreadingFactor": "Spreading Factor", + "repeater_codingRate": "Tasso di Codifica", + "repeater_locationSettings": "Impostazioni Luogo", + "repeater_latitude": "Latitudine", + "repeater_latitudeHelper": "Grado decimale (ad esempio, 37.7749)", + "repeater_longitude": "Longitudine", + "repeater_longitudeHelper": "Grado decimale (ad esempio, -122,4194)", + "repeater_features": "Caratteristiche", + "repeater_packetForwarding": "Instradamento Pacchetti", + "repeater_packetForwardingSubtitle": "Abilita il ripetitore per inoltrare i pacchetti", + "repeater_guestAccess": "Accesso Ospite", + "repeater_guestAccessSubtitle": "Consenti l'accesso ospite in sola lettura", + "repeater_privacyMode": "Modalità Privacy", + "repeater_privacyModeSubtitle": "Nascondere nome/luogo negli annunci", + "repeater_advertisementSettings": "Impostazioni Annuncio", + "repeater_localAdvertInterval": "Intervallo Pubblicità Locale", + "repeater_localAdvertIntervalMinutes": "{minutes} minuti", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Intervallo Pubblicità Inondazione", + "repeater_floodAdvertIntervalHours": "{hours} ore", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Intervallo Pubblicitario Crittografato", + "repeater_dangerZone": "Zona Pericolosa", + "repeater_rebootRepeater": "Riavvia Ripetitore", + "repeater_rebootRepeaterSubtitle": "Riavvia il dispositivo ripetitore", + "repeater_rebootRepeaterConfirm": "Sei sicuro di voler riavviare questo ripetitore?", + "repeater_regenerateIdentityKey": "Rigenera Chiave Identità", + "repeater_regenerateIdentityKeySubtitle": "Genera una nuova coppia di chiavi pubblica/privata", + "repeater_regenerateIdentityKeyConfirm": "Questo genererà una nuova identità per il ripetitore. Procedere?", + "repeater_eraseFileSystem": "Elimina File System", + "repeater_eraseFileSystemSubtitle": "Formatta il file system del ripetitore", + "repeater_eraseFileSystemConfirm": "ATTENZIONE: Ciò cancellerà tutti i dati sul ripetitore. Non può essere annullato!", + "repeater_eraseSerialOnly": "Elimina è disponibile solo tramite console seriale.", + "repeater_commandSent": "Comando inviato: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Errore nell'invio del comando: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "Conferma", + "repeater_settingsSaved": "Impostazioni salvate con successo", + "repeater_errorSavingSettings": "Errore durante il salvataggio delle impostazioni: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Aggiorna Impostazioni Base", + "repeater_refreshRadioSettings": "Aggiorna le Impostazioni Radio", + "repeater_refreshTxPower": "Aggiorna TX potenza", + "repeater_refreshLocationSettings": "Aggiorna le Impostazioni della Posizione", + "repeater_refreshPacketForwarding": "Aggiorna il inoltro pacchetti", + "repeater_refreshGuestAccess": "Aggiorna Accesso Ospite", + "repeater_refreshPrivacyMode": "Aggiorna Modalità Privacy", + "repeater_refreshAdvertisementSettings": "Aggiorna le Impostazioni dell'Annuncio", + "repeater_refreshed": "{label} aggiornato", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Errore durante il ricaricamento di {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Riprova CLI", + "repeater_debugNextCommand": "Riavvia Comando Prossimo", + "repeater_commandHelp": "Aiuto", + "repeater_clearHistory": "Cancella Cronologia", + "repeater_noCommandsSent": "Nessun comando inviato ancora", + "repeater_typeCommandOrUseQuick": "Digita un comando qui sotto o usa comandi rapidi", + "repeater_enterCommandHint": "Inserisci comando...", + "repeater_previousCommand": "Comando precedente", + "repeater_nextCommand": "Prossimo comando", + "repeater_enterCommandFirst": "Inserisci un comando prima", + "repeater_cliCommandFrameTitle": "Finestra Comando CLI", + "repeater_cliCommandError": "Errore: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Ottieni Nome", + "repeater_cliQuickGetRadio": "Ottieni Radio", + "repeater_cliQuickGetTx": "Ottieni TX", + "repeater_cliQuickNeighbors": "Vicini", + "repeater_cliQuickVersion": "Versione", + "repeater_cliQuickAdvertise": "Pubblicare", + "repeater_cliQuickClock": "Orologio", + "repeater_cliHelpAdvert": "Invia un pacchetto pubblicitario", + "repeater_cliHelpReboot": "Riavvia il dispositivo. (nota, potresti ottenere 'Timeout' che è normale)", + "repeater_cliHelpClock": "Mostra l'ora corrente per l'orologio di ciascun dispositivo.", + "repeater_cliHelpPassword": "Imposta una nuova password di amministratore per il dispositivo.", + "repeater_cliHelpVersion": "Mostra la versione del dispositivo e la data di costruzione del firmware.", + "repeater_cliHelpClearStats": "Resetta vari numerosi contatori di statistiche a zero.", + "repeater_cliHelpSetAf": "Imposta il fattore di tempo di trasmissione.", + "repeater_cliHelpSetTx": "Imposta la potenza di trasmissione LoRa in dBm (riavvia per applicare).", + "repeater_cliHelpSetRepeat": "Abilita o disabilita il ruolo del ripetitore per questo nodo.", + "repeater_cliHelpSetAllowReadOnly": "(Server della stanza) Se 'on', allora l'accesso con una password vuota sarà consentito, ma non sarà possibile pubblicare nella stanza. (solo lettura).", + "repeater_cliHelpSetFloodMax": "Imposta il numero massimo di salti per i pacchetti di inondazione in entrata (se >= max, il pacchetto non viene inoltrato)", + "repeater_cliHelpSetIntThresh": "Imposta il Limite di Interferenza (in dB). Il valore predefinito è 14. Imposta su 0 per disabilitare il rilevamento delle interferenze del canale.", + "repeater_cliHelpSetAgcResetInterval": "Imposta l'intervallo per resettare il controllore Automatico del Guadagno. Imposta su 0 per disabilitare.", + "repeater_cliHelpSetMultiAcks": "Abilita o disabilita la funzione 'double ACKs'.", + "repeater_cliHelpSetAdvertInterval": "Imposta l'intervallo del timer in minuti per inviare un pacchetto di pubblicità locale (senza salto). Imposta su 0 per disabilitare.", + "repeater_cliHelpSetFloodAdvertInterval": "Imposta l'intervallo del timer in ore per inviare un pacchetto pubblicitario di massa. Imposta su 0 per disabilitare.", + "repeater_cliHelpSetGuestPassword": "Imposta/aggiorna la password dell'ospite. (per ripetitori, gli accessi degli ospiti possono inviare la richiesta \"Get Stats\")", + "repeater_cliHelpSetName": "Imposta il nome dell'annuncio.", + "repeater_cliHelpSetLat": "Imposta la latitudine della mappa pubblicitaria. (gradi decimali)", + "repeater_cliHelpSetLon": "Imposta la longitudine della mappa pubblicitaria. (gradi decimali)", + "repeater_cliHelpSetRadio": "Imposta completamente nuovi parametri radio e li salva nelle preferenze. Richiede un comando \"reboot\" per l'applicazione.", + "repeater_cliHelpSetRxDelay": "Impostazioni (experimental) base (deve essere > 1 per l'effetto) per applicare un leggero ritardo ai pacchetti ricevuti, in base alla forza del segnale/punteggio. Imposta a 0 per disabilitare.", + "repeater_cliHelpSetTxDelay": "Imposta un fattore moltiplicato con il tempo di mantenimento per un pacchetto di modalità allagamento e con un sistema di slot casuale, per ritardarne la trasmissione (per diminuire la probabilità di collisioni).", + "repeater_cliHelpSetDirectTxDelay": "Uguale a txdelay, ma per applicare un ritardo casuale alla inoltrata di pacchetti in modalità diretta.", + "repeater_cliHelpSetBridgeEnabled": "Abilita/Disabilita ponte.", + "repeater_cliHelpSetBridgeDelay": "Imposta il ritardo prima di ritrasmettere i pacchetti.", + "repeater_cliHelpSetBridgeSource": "Scegliere se il ponte dovrà ritrasmettere i pacchetti ricevuti o i pacchetti trasmessi.", + "repeater_cliHelpSetBridgeBaud": "Imposta la velocità di trasmissione per i ponti rs232.", + "repeater_cliHelpSetBridgeSecret": "Imposta il segreto per i ponti espnow.", + "repeater_cliHelpSetAdcMultiplier": "Imposta un fattore personalizzato per regolare la tensione della batteria riportata (supportato solo su schede selezionate).", + "repeater_cliHelpTempRadio": "Imposta parametri radio temporanei per il numero specificato di minuti, per poi tornare ai parametri radio originali. (non salva nelle preferenze).", + "repeater_cliHelpSetPerm": "Modifica l'ACL. Rimuove l'entrata corrispondente (per prefisso di pubkey) se \"permissions\" è zero. Aggiunge una nuova entrata se il pubkey-hex ha lunghezza completa e non è attualmente nell'ACL. Aggiorna l'entrata per corrispondenza del prefisso di pubkey. I bit di permesso variano per ogni ruolo di firmware, ma i primi 2 bit sono: 0 (Guest), 1 (solo lettura), 2 (lettura/scrittura), 3 (Admin)", + "repeater_cliHelpGetBridgeType": "Ottiene tipo ponte nessuno, rs232, espnow", + "repeater_cliHelpLogStart": "Avvia registrazione pacchetti nel file system.", + "repeater_cliHelpLogStop": "Interrompi la registrazione dei pacchetti al file system.", + "repeater_cliHelpLogErase": "Elimina i log del pacchetto dal file system.", + "repeater_cliHelpNeighbors": "Mostra un elenco di altri nodi repeater ricevuti tramite annunci zero-hop. Ogni riga è id-prefisso-esadecimale:timestamp:snr-volte-4", + "repeater_cliHelpNeighborRemove": "Rimuove la prima corrispondenza in base al prefisso (esadecimale) della pubkey, dalla lista dei vicini.", + "repeater_cliHelpRegion": "(solo serie) Elenca tutte le regioni definite e le autorizzazioni di allagamento correnti.", + "repeater_cliHelpRegionLoad": "NOTA: questo è un'invocazione multi-comando speciale. Ogni comando successivo è un nome di regione (indentato con spazi per indicare la gerarchia parentale, con almeno uno spazio). Terminata inviando una riga vuota/comando.", + "repeater_cliHelpRegionGet": "Cerca la regione con il prefisso del nome dato (o \"\" per l'ambito globale). Risponde con \"-> nome-regione (nome-genitore) 'F'\"", + "repeater_cliHelpRegionPut": "Aggiunge o aggiorna una definizione di regione con il nome specificato.", + "repeater_cliHelpRegionRemove": "Rimuove una definizione di regione con il dato nome. (deve corrispondere esattamente e non avere regioni figlio)", + "repeater_cliHelpRegionAllowf": "Imposta il permesso di 'F'lood per la regione specificata. ('' per lo scope globale/legacy)", + "repeater_cliHelpRegionDenyf": "Rimuove il permesso 'F'lood per la regione specificata. (NOTA: a questo stadio non è consigliato utilizzarlo sullo scope globale/legacy!!).", + "repeater_cliHelpRegionHome": "Risposte con la regione 'home' corrente. (Nota applicata finora, riservata per il futuro)", + "repeater_cliHelpRegionHomeSet": "Imposta la regione 'home'.", + "repeater_cliHelpRegionSave": "Persiste l'elenco/mappa delle regioni all'archiviazione.", + "repeater_cliHelpGps": "Mostra lo stato del GPS. Quando il GPS è spento, risponde solo \"spento\", se è acceso risponde con \"acceso\", \"stato\", \"fix\" e numero di satelliti.", + "repeater_cliHelpGpsOnOff": "Attiva/disattiva l'alimentazione del GPS.", + "repeater_cliHelpGpsSync": "Sincronizza l'orario del nodo con l'orologio GPS.", + "repeater_cliHelpGpsSetLoc": "Imposta la posizione del nodo alle coordinate GPS e salva le preferenze.", + "repeater_cliHelpGpsAdvert": "Fornisce la configurazione dell'annuncio per il nodo:\n- nessuno: non includere la posizione negli annunci\n- condividi: condividi la posizione GPS (dal SensorManager)\n- preferenze: annuncia la posizione memorizzata nelle preferenze", + "repeater_cliHelpGpsAdvertSet": "Imposta la configurazione dell'annuncio sulla posizione.", + "repeater_commandsListTitle": "Elenco Comandi", + "repeater_commandsListNote": "NOTA: per i vari comandi \"set...\", esiste anche un comando \"get...\".", + "repeater_general": "Generale", + "repeater_settingsCategory": "Impostazioni", + "repeater_bridge": "Ponte", + "repeater_logging": "Registrazione", + "repeater_neighborsRepeaterOnly": "Vicini (solo ripetitore)", + "repeater_regionManagementRepeaterOnly": "Gestione Regione (solo Ripetitore)", + "repeater_regionNote": "Sono state introdotte le comandi di regione per gestire le definizioni e le autorizzazioni delle regioni.", + "repeater_gpsManagement": "Gestione GPS", + "repeater_gpsNote": "è stata introdotta una funzione gps per gestire le tematiche relative alla posizione.", + "telemetry_receivedData": "Dati Telemetria Ricevuti", + "telemetry_requestTimeout": "Richiesta di telemetria scaduta.", + "telemetry_errorLoading": "Errore nel caricamento della telemetria: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "Nessun dato di telemetria disponibile.", + "telemetry_channelTitle": "Canale {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Batteria", + "telemetry_voltageLabel": "Tensione", + "telemetry_mcuTemperatureLabel": "Temperatura MCU", + "telemetry_temperatureLabel": "Temperatura", + "telemetry_currentLabel": "Attuale", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Percorso Pacchetto", + "channelPath_viewMap": "Visualizza la mappa", + "channelPath_otherObservedPaths": "Altri Percorsi Osservati", + "channelPath_repeaterHops": "Passaggi Ripetitore", + "channelPath_noHopDetails": "I dettagli relativi a questo pacchetto non sono forniti.", + "channelPath_messageDetails": "Dettagli Messaggio", + "channelPath_senderLabel": "Mittente", + "channelPath_timeLabel": "Tempo", + "channelPath_repeatsLabel": "Ripeti", + "channelPath_pathLabel": "Percorso {index}", + "channelPath_observedLabel": "Osservato", + "channelPath_observedPathTitle": "Percorso osservato {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "Nessun dato di posizione", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Sconosciuto", + "channelPath_floodPath": "Inondazione", + "channelPath_directPath": "Salva", + "channelPath_observedZeroOf": "0 di {total} salti", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} di {total} salti", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Mappa del Percorso", + "channelPath_noRepeaterLocations": "Non sono disponibili posizioni per i ripetitori per questo percorso.", + "channelPath_primaryPath": "Percorso {index} (Primario)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Percorso", + "channelPath_observedPathHeader": "Percorso Osservato", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "Non sono disponibili i dettagli del salto per questo pacchetto.", + "channelPath_unknownRepeater": "Ripetitore sconosciuto", + "listFilter_tooltip": "Filtra e ordina", + "listFilter_sortBy": "Ordina per", + "listFilter_latestMessages": "Ultimi messaggi", + "listFilter_heardRecently": "Sentito di recente", + "listFilter_az": "A-Z", + "listFilter_filters": "Filtri", + "listFilter_all": "Tutti", + "listFilter_users": "Utenti", + "listFilter_repeaters": "Ripetitori", + "listFilter_roomServers": "Server della stanza", + "listFilter_unreadOnly": "Solo non letto", + "listFilter_newGroup": "Nuovo gruppo" +} diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart new file mode 100644 index 0000000..a2c7ddb --- /dev/null +++ b/lib/l10n/app_localizations.dart @@ -0,0 +1,4281 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:intl/intl.dart' as intl; + +import 'app_localizations_bg.dart'; +import 'app_localizations_de.dart'; +import 'app_localizations_en.dart'; +import 'app_localizations_es.dart'; +import 'app_localizations_fr.dart'; +import 'app_localizations_it.dart'; +import 'app_localizations_nl.dart'; +import 'app_localizations_pl.dart'; +import 'app_localizations_pt.dart'; +import 'app_localizations_sk.dart'; +import 'app_localizations_sl.dart'; +import 'app_localizations_sv.dart'; +import 'app_localizations_zh.dart'; + +// ignore_for_file: type=lint + +/// Callers can lookup localized strings with an instance of AppLocalizations +/// returned by `AppLocalizations.of(context)`. +/// +/// Applications need to include `AppLocalizations.delegate()` in their app's +/// `localizationDelegates` list, and the locales they support in the app's +/// `supportedLocales` list. For example: +/// +/// ```dart +/// import 'l10n/app_localizations.dart'; +/// +/// return MaterialApp( +/// localizationsDelegates: AppLocalizations.localizationsDelegates, +/// supportedLocales: AppLocalizations.supportedLocales, +/// home: MyApplicationHome(), +/// ); +/// ``` +/// +/// ## Update pubspec.yaml +/// +/// Please make sure to update your pubspec.yaml to include the following +/// packages: +/// +/// ```yaml +/// dependencies: +/// # Internationalization support. +/// flutter_localizations: +/// sdk: flutter +/// intl: any # Use the pinned version from flutter_localizations +/// +/// # Rest of dependencies +/// ``` +/// +/// ## iOS Applications +/// +/// iOS applications define key application metadata, including supported +/// locales, in an Info.plist file that is built into the application bundle. +/// To configure the locales supported by your app, you’ll need to edit this +/// file. +/// +/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file. +/// Then, in the Project Navigator, open the Info.plist file under the Runner +/// project’s Runner folder. +/// +/// Next, select the Information Property List item, select Add Item from the +/// Editor menu, then select Localizations from the pop-up menu. +/// +/// Select and expand the newly-created Localizations item then, for each +/// locale your application supports, add a new item and select the locale +/// you wish to add from the pop-up menu in the Value field. This list should +/// be consistent with the languages listed in the AppLocalizations.supportedLocales +/// property. +abstract class AppLocalizations { + AppLocalizations(String locale) + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + + final String localeName; + + static AppLocalizations of(BuildContext context) { + return Localizations.of(context, AppLocalizations)!; + } + + static const LocalizationsDelegate delegate = + _AppLocalizationsDelegate(); + + /// A list of this localizations delegate along with the default localizations + /// delegates. + /// + /// Returns a list of localizations delegates containing this delegate along with + /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, + /// and GlobalWidgetsLocalizations.delegate. + /// + /// Additional delegates can be added by appending to this list in + /// MaterialApp. This list does not have to be used at all if a custom list + /// of delegates is preferred or required. + static const List> localizationsDelegates = + >[ + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; + + /// A list of this localizations delegate's supported locales. + static const List supportedLocales = [ + Locale('bg'), + Locale('de'), + Locale('en'), + Locale('es'), + Locale('fr'), + Locale('it'), + Locale('nl'), + Locale('pl'), + Locale('pt'), + Locale('sk'), + Locale('sl'), + Locale('sv'), + Locale('zh'), + ]; + + /// No description provided for @appTitle. + /// + /// In en, this message translates to: + /// **'MeshCore Open'** + String get appTitle; + + /// No description provided for @nav_contacts. + /// + /// In en, this message translates to: + /// **'Contacts'** + String get nav_contacts; + + /// No description provided for @nav_channels. + /// + /// In en, this message translates to: + /// **'Channels'** + String get nav_channels; + + /// No description provided for @nav_map. + /// + /// In en, this message translates to: + /// **'Map'** + String get nav_map; + + /// No description provided for @common_cancel. + /// + /// In en, this message translates to: + /// **'Cancel'** + String get common_cancel; + + /// No description provided for @common_connect. + /// + /// In en, this message translates to: + /// **'Connect'** + String get common_connect; + + /// No description provided for @common_unknownDevice. + /// + /// In en, this message translates to: + /// **'Unknown Device'** + String get common_unknownDevice; + + /// No description provided for @common_save. + /// + /// In en, this message translates to: + /// **'Save'** + String get common_save; + + /// No description provided for @common_delete. + /// + /// In en, this message translates to: + /// **'Delete'** + String get common_delete; + + /// No description provided for @common_close. + /// + /// In en, this message translates to: + /// **'Close'** + String get common_close; + + /// No description provided for @common_edit. + /// + /// In en, this message translates to: + /// **'Edit'** + String get common_edit; + + /// No description provided for @common_add. + /// + /// In en, this message translates to: + /// **'Add'** + String get common_add; + + /// No description provided for @common_settings. + /// + /// In en, this message translates to: + /// **'Settings'** + String get common_settings; + + /// No description provided for @common_disconnect. + /// + /// In en, this message translates to: + /// **'Disconnect'** + String get common_disconnect; + + /// No description provided for @common_connected. + /// + /// In en, this message translates to: + /// **'Connected'** + String get common_connected; + + /// No description provided for @common_disconnected. + /// + /// In en, this message translates to: + /// **'Disconnected'** + String get common_disconnected; + + /// No description provided for @common_create. + /// + /// In en, this message translates to: + /// **'Create'** + String get common_create; + + /// No description provided for @common_continue. + /// + /// In en, this message translates to: + /// **'Continue'** + String get common_continue; + + /// No description provided for @common_share. + /// + /// In en, this message translates to: + /// **'Share'** + String get common_share; + + /// No description provided for @common_copy. + /// + /// In en, this message translates to: + /// **'Copy'** + String get common_copy; + + /// No description provided for @common_retry. + /// + /// In en, this message translates to: + /// **'Retry'** + String get common_retry; + + /// No description provided for @common_hide. + /// + /// In en, this message translates to: + /// **'Hide'** + String get common_hide; + + /// No description provided for @common_remove. + /// + /// In en, this message translates to: + /// **'Remove'** + String get common_remove; + + /// No description provided for @common_enable. + /// + /// In en, this message translates to: + /// **'Enable'** + String get common_enable; + + /// No description provided for @common_disable. + /// + /// In en, this message translates to: + /// **'Disable'** + String get common_disable; + + /// No description provided for @common_reboot. + /// + /// In en, this message translates to: + /// **'Reboot'** + String get common_reboot; + + /// No description provided for @common_loading. + /// + /// In en, this message translates to: + /// **'Loading...'** + String get common_loading; + + /// No description provided for @common_notAvailable. + /// + /// In en, this message translates to: + /// **'—'** + String get common_notAvailable; + + /// No description provided for @common_voltageValue. + /// + /// In en, this message translates to: + /// **'{volts} V'** + String common_voltageValue(String volts); + + /// No description provided for @common_percentValue. + /// + /// In en, this message translates to: + /// **'{percent}%'** + String common_percentValue(int percent); + + /// No description provided for @scanner_title. + /// + /// In en, this message translates to: + /// **'MeshCore Open'** + String get scanner_title; + + /// No description provided for @scanner_scanning. + /// + /// In en, this message translates to: + /// **'Scanning for devices...'** + String get scanner_scanning; + + /// No description provided for @scanner_connecting. + /// + /// In en, this message translates to: + /// **'Connecting...'** + String get scanner_connecting; + + /// No description provided for @scanner_disconnecting. + /// + /// In en, this message translates to: + /// **'Disconnecting...'** + String get scanner_disconnecting; + + /// No description provided for @scanner_notConnected. + /// + /// In en, this message translates to: + /// **'Not connected'** + String get scanner_notConnected; + + /// No description provided for @scanner_connectedTo. + /// + /// In en, this message translates to: + /// **'Connected to {deviceName}'** + String scanner_connectedTo(String deviceName); + + /// No description provided for @scanner_searchingDevices. + /// + /// In en, this message translates to: + /// **'Searching for MeshCore devices...'** + String get scanner_searchingDevices; + + /// No description provided for @scanner_tapToScan. + /// + /// In en, this message translates to: + /// **'Tap Scan to find MeshCore devices'** + String get scanner_tapToScan; + + /// No description provided for @scanner_connectionFailed. + /// + /// In en, this message translates to: + /// **'Connection failed: {error}'** + String scanner_connectionFailed(String error); + + /// No description provided for @scanner_stop. + /// + /// In en, this message translates to: + /// **'Stop'** + String get scanner_stop; + + /// No description provided for @scanner_scan. + /// + /// In en, this message translates to: + /// **'Scan'** + String get scanner_scan; + + /// No description provided for @device_quickSwitch. + /// + /// In en, this message translates to: + /// **'Quick switch'** + String get device_quickSwitch; + + /// No description provided for @device_meshcore. + /// + /// In en, this message translates to: + /// **'MeshCore'** + String get device_meshcore; + + /// No description provided for @settings_title. + /// + /// In en, this message translates to: + /// **'Settings'** + String get settings_title; + + /// No description provided for @settings_deviceInfo. + /// + /// In en, this message translates to: + /// **'Device Info'** + String get settings_deviceInfo; + + /// No description provided for @settings_appSettings. + /// + /// In en, this message translates to: + /// **'App Settings'** + String get settings_appSettings; + + /// No description provided for @settings_appSettingsSubtitle. + /// + /// In en, this message translates to: + /// **'Notifications, messaging, and map preferences'** + String get settings_appSettingsSubtitle; + + /// No description provided for @settings_nodeSettings. + /// + /// In en, this message translates to: + /// **'Node Settings'** + String get settings_nodeSettings; + + /// No description provided for @settings_nodeName. + /// + /// In en, this message translates to: + /// **'Node Name'** + String get settings_nodeName; + + /// No description provided for @settings_nodeNameNotSet. + /// + /// In en, this message translates to: + /// **'Not set'** + String get settings_nodeNameNotSet; + + /// No description provided for @settings_nodeNameHint. + /// + /// In en, this message translates to: + /// **'Enter node name'** + String get settings_nodeNameHint; + + /// No description provided for @settings_nodeNameUpdated. + /// + /// In en, this message translates to: + /// **'Name updated'** + String get settings_nodeNameUpdated; + + /// No description provided for @settings_radioSettings. + /// + /// In en, this message translates to: + /// **'Radio Settings'** + String get settings_radioSettings; + + /// No description provided for @settings_radioSettingsSubtitle. + /// + /// In en, this message translates to: + /// **'Frequency, power, spreading factor'** + String get settings_radioSettingsSubtitle; + + /// No description provided for @settings_radioSettingsUpdated. + /// + /// In en, this message translates to: + /// **'Radio settings updated'** + String get settings_radioSettingsUpdated; + + /// No description provided for @settings_location. + /// + /// In en, this message translates to: + /// **'Location'** + String get settings_location; + + /// No description provided for @settings_locationSubtitle. + /// + /// In en, this message translates to: + /// **'GPS coordinates'** + String get settings_locationSubtitle; + + /// No description provided for @settings_locationUpdated. + /// + /// In en, this message translates to: + /// **'Location updated'** + String get settings_locationUpdated; + + /// No description provided for @settings_locationBothRequired. + /// + /// In en, this message translates to: + /// **'Enter both latitude and longitude.'** + String get settings_locationBothRequired; + + /// No description provided for @settings_locationInvalid. + /// + /// In en, this message translates to: + /// **'Invalid latitude or longitude.'** + String get settings_locationInvalid; + + /// No description provided for @settings_latitude. + /// + /// In en, this message translates to: + /// **'Latitude'** + String get settings_latitude; + + /// No description provided for @settings_longitude. + /// + /// In en, this message translates to: + /// **'Longitude'** + String get settings_longitude; + + /// No description provided for @settings_privacyMode. + /// + /// In en, this message translates to: + /// **'Privacy Mode'** + String get settings_privacyMode; + + /// No description provided for @settings_privacyModeSubtitle. + /// + /// In en, this message translates to: + /// **'Hide name/location in advertisements'** + String get settings_privacyModeSubtitle; + + /// No description provided for @settings_privacyModeToggle. + /// + /// In en, this message translates to: + /// **'Toggle privacy mode to hide your name and location in advertisements.'** + String get settings_privacyModeToggle; + + /// No description provided for @settings_privacyModeEnabled. + /// + /// In en, this message translates to: + /// **'Privacy mode enabled'** + String get settings_privacyModeEnabled; + + /// No description provided for @settings_privacyModeDisabled. + /// + /// In en, this message translates to: + /// **'Privacy mode disabled'** + String get settings_privacyModeDisabled; + + /// No description provided for @settings_actions. + /// + /// In en, this message translates to: + /// **'Actions'** + String get settings_actions; + + /// No description provided for @settings_sendAdvertisement. + /// + /// In en, this message translates to: + /// **'Send Advertisement'** + String get settings_sendAdvertisement; + + /// No description provided for @settings_sendAdvertisementSubtitle. + /// + /// In en, this message translates to: + /// **'Broadcast presence now'** + String get settings_sendAdvertisementSubtitle; + + /// No description provided for @settings_advertisementSent. + /// + /// In en, this message translates to: + /// **'Advertisement sent'** + String get settings_advertisementSent; + + /// No description provided for @settings_syncTime. + /// + /// In en, this message translates to: + /// **'Sync Time'** + String get settings_syncTime; + + /// No description provided for @settings_syncTimeSubtitle. + /// + /// In en, this message translates to: + /// **'Set device clock to phone time'** + String get settings_syncTimeSubtitle; + + /// No description provided for @settings_timeSynchronized. + /// + /// In en, this message translates to: + /// **'Time synchronized'** + String get settings_timeSynchronized; + + /// No description provided for @settings_refreshContacts. + /// + /// In en, this message translates to: + /// **'Refresh Contacts'** + String get settings_refreshContacts; + + /// No description provided for @settings_refreshContactsSubtitle. + /// + /// In en, this message translates to: + /// **'Reload contact list from device'** + String get settings_refreshContactsSubtitle; + + /// No description provided for @settings_rebootDevice. + /// + /// In en, this message translates to: + /// **'Reboot Device'** + String get settings_rebootDevice; + + /// No description provided for @settings_rebootDeviceSubtitle. + /// + /// In en, this message translates to: + /// **'Restart the MeshCore device'** + String get settings_rebootDeviceSubtitle; + + /// No description provided for @settings_rebootDeviceConfirm. + /// + /// In en, this message translates to: + /// **'Are you sure you want to reboot the device? You will be disconnected.'** + String get settings_rebootDeviceConfirm; + + /// No description provided for @settings_debug. + /// + /// In en, this message translates to: + /// **'Debug'** + String get settings_debug; + + /// No description provided for @settings_bleDebugLog. + /// + /// In en, this message translates to: + /// **'BLE Debug Log'** + String get settings_bleDebugLog; + + /// No description provided for @settings_bleDebugLogSubtitle. + /// + /// In en, this message translates to: + /// **'BLE commands, responses, and raw data'** + String get settings_bleDebugLogSubtitle; + + /// No description provided for @settings_appDebugLog. + /// + /// In en, this message translates to: + /// **'App Debug Log'** + String get settings_appDebugLog; + + /// No description provided for @settings_appDebugLogSubtitle. + /// + /// In en, this message translates to: + /// **'Application debug messages'** + String get settings_appDebugLogSubtitle; + + /// No description provided for @settings_about. + /// + /// In en, this message translates to: + /// **'About'** + String get settings_about; + + /// No description provided for @settings_aboutVersion. + /// + /// In en, this message translates to: + /// **'MeshCore Open v{version}'** + String settings_aboutVersion(String version); + + /// No description provided for @settings_aboutLegalese. + /// + /// In en, this message translates to: + /// **'2026 MeshCore Open Source Project'** + String get settings_aboutLegalese; + + /// No description provided for @settings_aboutDescription. + /// + /// In en, this message translates to: + /// **'An open-source Flutter client for MeshCore LoRa mesh networking devices.'** + String get settings_aboutDescription; + + /// No description provided for @settings_infoName. + /// + /// In en, this message translates to: + /// **'Name'** + String get settings_infoName; + + /// No description provided for @settings_infoId. + /// + /// In en, this message translates to: + /// **'ID'** + String get settings_infoId; + + /// No description provided for @settings_infoStatus. + /// + /// In en, this message translates to: + /// **'Status'** + String get settings_infoStatus; + + /// No description provided for @settings_infoBattery. + /// + /// In en, this message translates to: + /// **'Battery'** + String get settings_infoBattery; + + /// No description provided for @settings_infoPublicKey. + /// + /// In en, this message translates to: + /// **'Public Key'** + String get settings_infoPublicKey; + + /// No description provided for @settings_infoContactsCount. + /// + /// In en, this message translates to: + /// **'Contacts Count'** + String get settings_infoContactsCount; + + /// No description provided for @settings_infoChannelCount. + /// + /// In en, this message translates to: + /// **'Channel Count'** + String get settings_infoChannelCount; + + /// No description provided for @settings_presets. + /// + /// In en, this message translates to: + /// **'Presets'** + String get settings_presets; + + /// No description provided for @settings_preset915Mhz. + /// + /// In en, this message translates to: + /// **'915 MHz'** + String get settings_preset915Mhz; + + /// No description provided for @settings_preset868Mhz. + /// + /// In en, this message translates to: + /// **'868 MHz'** + String get settings_preset868Mhz; + + /// No description provided for @settings_preset433Mhz. + /// + /// In en, this message translates to: + /// **'433 MHz'** + String get settings_preset433Mhz; + + /// No description provided for @settings_frequency. + /// + /// In en, this message translates to: + /// **'Frequency (MHz)'** + String get settings_frequency; + + /// No description provided for @settings_frequencyHelper. + /// + /// In en, this message translates to: + /// **'300.0 - 2500.0'** + String get settings_frequencyHelper; + + /// No description provided for @settings_frequencyInvalid. + /// + /// In en, this message translates to: + /// **'Invalid frequency (300-2500 MHz)'** + String get settings_frequencyInvalid; + + /// No description provided for @settings_bandwidth. + /// + /// In en, this message translates to: + /// **'Bandwidth'** + String get settings_bandwidth; + + /// No description provided for @settings_spreadingFactor. + /// + /// In en, this message translates to: + /// **'Spreading Factor'** + String get settings_spreadingFactor; + + /// No description provided for @settings_codingRate. + /// + /// In en, this message translates to: + /// **'Coding Rate'** + String get settings_codingRate; + + /// No description provided for @settings_txPower. + /// + /// In en, this message translates to: + /// **'TX Power (dBm)'** + String get settings_txPower; + + /// No description provided for @settings_txPowerHelper. + /// + /// In en, this message translates to: + /// **'0 - 22'** + String get settings_txPowerHelper; + + /// No description provided for @settings_txPowerInvalid. + /// + /// In en, this message translates to: + /// **'Invalid TX power (0-22 dBm)'** + String get settings_txPowerInvalid; + + /// No description provided for @settings_longRange. + /// + /// In en, this message translates to: + /// **'Long Range'** + String get settings_longRange; + + /// No description provided for @settings_fastSpeed. + /// + /// In en, this message translates to: + /// **'Fast Speed'** + String get settings_fastSpeed; + + /// No description provided for @settings_error. + /// + /// In en, this message translates to: + /// **'Error: {message}'** + String settings_error(String message); + + /// No description provided for @appSettings_title. + /// + /// In en, this message translates to: + /// **'App Settings'** + String get appSettings_title; + + /// No description provided for @appSettings_appearance. + /// + /// In en, this message translates to: + /// **'Appearance'** + String get appSettings_appearance; + + /// No description provided for @appSettings_theme. + /// + /// In en, this message translates to: + /// **'Theme'** + String get appSettings_theme; + + /// No description provided for @appSettings_themeSystem. + /// + /// In en, this message translates to: + /// **'System default'** + String get appSettings_themeSystem; + + /// No description provided for @appSettings_themeLight. + /// + /// In en, this message translates to: + /// **'Light'** + String get appSettings_themeLight; + + /// No description provided for @appSettings_themeDark. + /// + /// In en, this message translates to: + /// **'Dark'** + String get appSettings_themeDark; + + /// No description provided for @appSettings_language. + /// + /// In en, this message translates to: + /// **'Language'** + String get appSettings_language; + + /// No description provided for @appSettings_languageSystem. + /// + /// In en, this message translates to: + /// **'System default'** + String get appSettings_languageSystem; + + /// No description provided for @appSettings_languageEn. + /// + /// In en, this message translates to: + /// **'English'** + String get appSettings_languageEn; + + /// No description provided for @appSettings_languageFr. + /// + /// In en, this message translates to: + /// **'Français'** + String get appSettings_languageFr; + + /// No description provided for @appSettings_languageEs. + /// + /// In en, this message translates to: + /// **'Español'** + String get appSettings_languageEs; + + /// No description provided for @appSettings_languageDe. + /// + /// In en, this message translates to: + /// **'Deutsch'** + String get appSettings_languageDe; + + /// No description provided for @appSettings_languagePl. + /// + /// In en, this message translates to: + /// **'Polski'** + String get appSettings_languagePl; + + /// No description provided for @appSettings_languageSl. + /// + /// In en, this message translates to: + /// **'Slovenščina'** + String get appSettings_languageSl; + + /// No description provided for @appSettings_languagePt. + /// + /// In en, this message translates to: + /// **'Português'** + String get appSettings_languagePt; + + /// No description provided for @appSettings_languageIt. + /// + /// In en, this message translates to: + /// **'Italiano'** + String get appSettings_languageIt; + + /// No description provided for @appSettings_languageZh. + /// + /// In en, this message translates to: + /// **'中文'** + String get appSettings_languageZh; + + /// No description provided for @appSettings_languageSv. + /// + /// In en, this message translates to: + /// **'Svenska'** + String get appSettings_languageSv; + + /// No description provided for @appSettings_languageNl. + /// + /// In en, this message translates to: + /// **'Nederlands'** + String get appSettings_languageNl; + + /// No description provided for @appSettings_languageSk. + /// + /// In en, this message translates to: + /// **'Slovenčina'** + String get appSettings_languageSk; + + /// No description provided for @appSettings_languageBg. + /// + /// In en, this message translates to: + /// **'Български'** + String get appSettings_languageBg; + + /// No description provided for @appSettings_notifications. + /// + /// In en, this message translates to: + /// **'Notifications'** + String get appSettings_notifications; + + /// No description provided for @appSettings_enableNotifications. + /// + /// In en, this message translates to: + /// **'Enable Notifications'** + String get appSettings_enableNotifications; + + /// No description provided for @appSettings_enableNotificationsSubtitle. + /// + /// In en, this message translates to: + /// **'Receive notifications for messages and adverts'** + String get appSettings_enableNotificationsSubtitle; + + /// No description provided for @appSettings_notificationPermissionDenied. + /// + /// In en, this message translates to: + /// **'Notification permission denied'** + String get appSettings_notificationPermissionDenied; + + /// No description provided for @appSettings_notificationsEnabled. + /// + /// In en, this message translates to: + /// **'Notifications enabled'** + String get appSettings_notificationsEnabled; + + /// No description provided for @appSettings_notificationsDisabled. + /// + /// In en, this message translates to: + /// **'Notifications disabled'** + String get appSettings_notificationsDisabled; + + /// No description provided for @appSettings_messageNotifications. + /// + /// In en, this message translates to: + /// **'Message Notifications'** + String get appSettings_messageNotifications; + + /// No description provided for @appSettings_messageNotificationsSubtitle. + /// + /// In en, this message translates to: + /// **'Show notification when receiving new messages'** + String get appSettings_messageNotificationsSubtitle; + + /// No description provided for @appSettings_channelMessageNotifications. + /// + /// In en, this message translates to: + /// **'Channel Message Notifications'** + String get appSettings_channelMessageNotifications; + + /// No description provided for @appSettings_channelMessageNotificationsSubtitle. + /// + /// In en, this message translates to: + /// **'Show notification when receiving channel messages'** + String get appSettings_channelMessageNotificationsSubtitle; + + /// No description provided for @appSettings_advertisementNotifications. + /// + /// In en, this message translates to: + /// **'Advertisement Notifications'** + String get appSettings_advertisementNotifications; + + /// No description provided for @appSettings_advertisementNotificationsSubtitle. + /// + /// In en, this message translates to: + /// **'Show notification when new nodes are discovered'** + String get appSettings_advertisementNotificationsSubtitle; + + /// No description provided for @appSettings_messaging. + /// + /// In en, this message translates to: + /// **'Messaging'** + String get appSettings_messaging; + + /// No description provided for @appSettings_clearPathOnMaxRetry. + /// + /// In en, this message translates to: + /// **'Clear Path on Max Retry'** + String get appSettings_clearPathOnMaxRetry; + + /// No description provided for @appSettings_clearPathOnMaxRetrySubtitle. + /// + /// In en, this message translates to: + /// **'Reset contact path after 5 failed send attempts'** + String get appSettings_clearPathOnMaxRetrySubtitle; + + /// No description provided for @appSettings_pathsWillBeCleared. + /// + /// In en, this message translates to: + /// **'Paths will be cleared after 5 failed retries'** + String get appSettings_pathsWillBeCleared; + + /// No description provided for @appSettings_pathsWillNotBeCleared. + /// + /// In en, this message translates to: + /// **'Paths will not be auto-cleared'** + String get appSettings_pathsWillNotBeCleared; + + /// No description provided for @appSettings_autoRouteRotation. + /// + /// In en, this message translates to: + /// **'Auto Route Rotation'** + String get appSettings_autoRouteRotation; + + /// No description provided for @appSettings_autoRouteRotationSubtitle. + /// + /// In en, this message translates to: + /// **'Cycle between best paths and flood mode'** + String get appSettings_autoRouteRotationSubtitle; + + /// No description provided for @appSettings_autoRouteRotationEnabled. + /// + /// In en, this message translates to: + /// **'Auto route rotation enabled'** + String get appSettings_autoRouteRotationEnabled; + + /// No description provided for @appSettings_autoRouteRotationDisabled. + /// + /// In en, this message translates to: + /// **'Auto route rotation disabled'** + String get appSettings_autoRouteRotationDisabled; + + /// No description provided for @appSettings_battery. + /// + /// In en, this message translates to: + /// **'Battery'** + String get appSettings_battery; + + /// No description provided for @appSettings_batteryChemistry. + /// + /// In en, this message translates to: + /// **'Battery Chemistry'** + String get appSettings_batteryChemistry; + + /// No description provided for @appSettings_batteryChemistryPerDevice. + /// + /// In en, this message translates to: + /// **'Set per device ({deviceName})'** + String appSettings_batteryChemistryPerDevice(String deviceName); + + /// No description provided for @appSettings_batteryChemistryConnectFirst. + /// + /// In en, this message translates to: + /// **'Connect to a device to choose'** + String get appSettings_batteryChemistryConnectFirst; + + /// No description provided for @appSettings_batteryNmc. + /// + /// In en, this message translates to: + /// **'18650 NMC (3.0-4.2V)'** + String get appSettings_batteryNmc; + + /// No description provided for @appSettings_batteryLifepo4. + /// + /// In en, this message translates to: + /// **'LiFePO4 (2.6-3.65V)'** + String get appSettings_batteryLifepo4; + + /// No description provided for @appSettings_batteryLipo. + /// + /// In en, this message translates to: + /// **'LiPo (3.0-4.2V)'** + String get appSettings_batteryLipo; + + /// No description provided for @appSettings_mapDisplay. + /// + /// In en, this message translates to: + /// **'Map Display'** + String get appSettings_mapDisplay; + + /// No description provided for @appSettings_showRepeaters. + /// + /// In en, this message translates to: + /// **'Show Repeaters'** + String get appSettings_showRepeaters; + + /// No description provided for @appSettings_showRepeatersSubtitle. + /// + /// In en, this message translates to: + /// **'Display repeater nodes on the map'** + String get appSettings_showRepeatersSubtitle; + + /// No description provided for @appSettings_showChatNodes. + /// + /// In en, this message translates to: + /// **'Show Chat Nodes'** + String get appSettings_showChatNodes; + + /// No description provided for @appSettings_showChatNodesSubtitle. + /// + /// In en, this message translates to: + /// **'Display chat nodes on the map'** + String get appSettings_showChatNodesSubtitle; + + /// No description provided for @appSettings_showOtherNodes. + /// + /// In en, this message translates to: + /// **'Show Other Nodes'** + String get appSettings_showOtherNodes; + + /// No description provided for @appSettings_showOtherNodesSubtitle. + /// + /// In en, this message translates to: + /// **'Display other node types on the map'** + String get appSettings_showOtherNodesSubtitle; + + /// No description provided for @appSettings_timeFilter. + /// + /// In en, this message translates to: + /// **'Time Filter'** + String get appSettings_timeFilter; + + /// No description provided for @appSettings_timeFilterShowAll. + /// + /// In en, this message translates to: + /// **'Show all nodes'** + String get appSettings_timeFilterShowAll; + + /// No description provided for @appSettings_timeFilterShowLast. + /// + /// In en, this message translates to: + /// **'Show nodes from last {hours} hours'** + String appSettings_timeFilterShowLast(int hours); + + /// No description provided for @appSettings_mapTimeFilter. + /// + /// In en, this message translates to: + /// **'Map Time Filter'** + String get appSettings_mapTimeFilter; + + /// No description provided for @appSettings_showNodesDiscoveredWithin. + /// + /// In en, this message translates to: + /// **'Show nodes discovered within:'** + String get appSettings_showNodesDiscoveredWithin; + + /// No description provided for @appSettings_allTime. + /// + /// In en, this message translates to: + /// **'All time'** + String get appSettings_allTime; + + /// No description provided for @appSettings_lastHour. + /// + /// In en, this message translates to: + /// **'Last hour'** + String get appSettings_lastHour; + + /// No description provided for @appSettings_last6Hours. + /// + /// In en, this message translates to: + /// **'Last 6 hours'** + String get appSettings_last6Hours; + + /// No description provided for @appSettings_last24Hours. + /// + /// In en, this message translates to: + /// **'Last 24 hours'** + String get appSettings_last24Hours; + + /// No description provided for @appSettings_lastWeek. + /// + /// In en, this message translates to: + /// **'Last week'** + String get appSettings_lastWeek; + + /// No description provided for @appSettings_offlineMapCache. + /// + /// In en, this message translates to: + /// **'Offline Map Cache'** + String get appSettings_offlineMapCache; + + /// No description provided for @appSettings_noAreaSelected. + /// + /// In en, this message translates to: + /// **'No area selected'** + String get appSettings_noAreaSelected; + + /// No description provided for @appSettings_areaSelectedZoom. + /// + /// In en, this message translates to: + /// **'Area selected (zoom {minZoom}-{maxZoom})'** + String appSettings_areaSelectedZoom(int minZoom, int maxZoom); + + /// No description provided for @appSettings_debugCard. + /// + /// In en, this message translates to: + /// **'Debug'** + String get appSettings_debugCard; + + /// No description provided for @appSettings_appDebugLogging. + /// + /// In en, this message translates to: + /// **'App Debug Logging'** + String get appSettings_appDebugLogging; + + /// No description provided for @appSettings_appDebugLoggingSubtitle. + /// + /// In en, this message translates to: + /// **'Log app debug messages for troubleshooting'** + String get appSettings_appDebugLoggingSubtitle; + + /// No description provided for @appSettings_appDebugLoggingEnabled. + /// + /// In en, this message translates to: + /// **'App debug logging enabled'** + String get appSettings_appDebugLoggingEnabled; + + /// No description provided for @appSettings_appDebugLoggingDisabled. + /// + /// In en, this message translates to: + /// **'App debug logging disabled'** + String get appSettings_appDebugLoggingDisabled; + + /// No description provided for @contacts_title. + /// + /// In en, this message translates to: + /// **'Contacts'** + String get contacts_title; + + /// No description provided for @contacts_noContacts. + /// + /// In en, this message translates to: + /// **'No contacts yet'** + String get contacts_noContacts; + + /// No description provided for @contacts_contactsWillAppear. + /// + /// In en, this message translates to: + /// **'Contacts will appear when devices advertise'** + String get contacts_contactsWillAppear; + + /// No description provided for @contacts_searchContacts. + /// + /// In en, this message translates to: + /// **'Search contacts...'** + String get contacts_searchContacts; + + /// No description provided for @contacts_noUnreadContacts. + /// + /// In en, this message translates to: + /// **'No unread contacts'** + String get contacts_noUnreadContacts; + + /// No description provided for @contacts_noContactsFound. + /// + /// In en, this message translates to: + /// **'No contacts or groups found'** + String get contacts_noContactsFound; + + /// No description provided for @contacts_deleteContact. + /// + /// In en, this message translates to: + /// **'Delete Contact'** + String get contacts_deleteContact; + + /// No description provided for @contacts_removeConfirm. + /// + /// In en, this message translates to: + /// **'Remove {contactName} from contacts?'** + String contacts_removeConfirm(String contactName); + + /// No description provided for @contacts_manageRepeater. + /// + /// In en, this message translates to: + /// **'Manage Repeater'** + String get contacts_manageRepeater; + + /// No description provided for @contacts_roomLogin. + /// + /// In en, this message translates to: + /// **'Room Login'** + String get contacts_roomLogin; + + /// No description provided for @contacts_openChat. + /// + /// In en, this message translates to: + /// **'Open Chat'** + String get contacts_openChat; + + /// No description provided for @contacts_editGroup. + /// + /// In en, this message translates to: + /// **'Edit Group'** + String get contacts_editGroup; + + /// No description provided for @contacts_deleteGroup. + /// + /// In en, this message translates to: + /// **'Delete Group'** + String get contacts_deleteGroup; + + /// No description provided for @contacts_deleteGroupConfirm. + /// + /// In en, this message translates to: + /// **'Remove \"{groupName}\"?'** + String contacts_deleteGroupConfirm(String groupName); + + /// No description provided for @contacts_newGroup. + /// + /// In en, this message translates to: + /// **'New Group'** + String get contacts_newGroup; + + /// No description provided for @contacts_groupName. + /// + /// In en, this message translates to: + /// **'Group name'** + String get contacts_groupName; + + /// No description provided for @contacts_groupNameRequired. + /// + /// In en, this message translates to: + /// **'Group name is required'** + String get contacts_groupNameRequired; + + /// No description provided for @contacts_groupAlreadyExists. + /// + /// In en, this message translates to: + /// **'Group \"{name}\" already exists'** + String contacts_groupAlreadyExists(String name); + + /// No description provided for @contacts_filterContacts. + /// + /// In en, this message translates to: + /// **'Filter contacts...'** + String get contacts_filterContacts; + + /// No description provided for @contacts_noContactsMatchFilter. + /// + /// In en, this message translates to: + /// **'No contacts match your filter'** + String get contacts_noContactsMatchFilter; + + /// No description provided for @contacts_noMembers. + /// + /// In en, this message translates to: + /// **'No members'** + String get contacts_noMembers; + + /// No description provided for @contacts_lastSeenNow. + /// + /// In en, this message translates to: + /// **'Last seen now'** + String get contacts_lastSeenNow; + + /// No description provided for @contacts_lastSeenMinsAgo. + /// + /// In en, this message translates to: + /// **'Last seen {minutes} mins ago'** + String contacts_lastSeenMinsAgo(int minutes); + + /// No description provided for @contacts_lastSeenHourAgo. + /// + /// In en, this message translates to: + /// **'Last seen 1 hour ago'** + String get contacts_lastSeenHourAgo; + + /// No description provided for @contacts_lastSeenHoursAgo. + /// + /// In en, this message translates to: + /// **'Last seen {hours} hours ago'** + String contacts_lastSeenHoursAgo(int hours); + + /// No description provided for @contacts_lastSeenDayAgo. + /// + /// In en, this message translates to: + /// **'Last seen 1 day ago'** + String get contacts_lastSeenDayAgo; + + /// No description provided for @contacts_lastSeenDaysAgo. + /// + /// In en, this message translates to: + /// **'Last seen {days} days ago'** + String contacts_lastSeenDaysAgo(int days); + + /// No description provided for @channels_title. + /// + /// In en, this message translates to: + /// **'Channels'** + String get channels_title; + + /// No description provided for @channels_noChannelsConfigured. + /// + /// In en, this message translates to: + /// **'No channels configured'** + String get channels_noChannelsConfigured; + + /// No description provided for @channels_addPublicChannel. + /// + /// In en, this message translates to: + /// **'Add Public Channel'** + String get channels_addPublicChannel; + + /// No description provided for @channels_searchChannels. + /// + /// In en, this message translates to: + /// **'Search channels...'** + String get channels_searchChannels; + + /// No description provided for @channels_noChannelsFound. + /// + /// In en, this message translates to: + /// **'No channels found'** + String get channels_noChannelsFound; + + /// No description provided for @channels_channelIndex. + /// + /// In en, this message translates to: + /// **'Channel {index}'** + String channels_channelIndex(int index); + + /// No description provided for @channels_hashtagChannel. + /// + /// In en, this message translates to: + /// **'Hashtag channel'** + String get channels_hashtagChannel; + + /// No description provided for @channels_public. + /// + /// In en, this message translates to: + /// **'Public'** + String get channels_public; + + /// No description provided for @channels_private. + /// + /// In en, this message translates to: + /// **'Private'** + String get channels_private; + + /// No description provided for @channels_publicChannel. + /// + /// In en, this message translates to: + /// **'Public channel'** + String get channels_publicChannel; + + /// No description provided for @channels_privateChannel. + /// + /// In en, this message translates to: + /// **'Private channel'** + String get channels_privateChannel; + + /// No description provided for @channels_editChannel. + /// + /// In en, this message translates to: + /// **'Edit channel'** + String get channels_editChannel; + + /// No description provided for @channels_deleteChannel. + /// + /// In en, this message translates to: + /// **'Delete channel'** + String get channels_deleteChannel; + + /// No description provided for @channels_deleteChannelConfirm. + /// + /// In en, this message translates to: + /// **'Delete \"{name}\"? This cannot be undone.'** + String channels_deleteChannelConfirm(String name); + + /// No description provided for @channels_channelDeleted. + /// + /// In en, this message translates to: + /// **'Channel \"{name}\" deleted'** + String channels_channelDeleted(String name); + + /// No description provided for @channels_addChannel. + /// + /// In en, this message translates to: + /// **'Add Channel'** + String get channels_addChannel; + + /// No description provided for @channels_channelIndexLabel. + /// + /// In en, this message translates to: + /// **'Channel Index'** + String get channels_channelIndexLabel; + + /// No description provided for @channels_channelName. + /// + /// In en, this message translates to: + /// **'Channel Name'** + String get channels_channelName; + + /// No description provided for @channels_usePublicChannel. + /// + /// In en, this message translates to: + /// **'Use Public Channel'** + String get channels_usePublicChannel; + + /// No description provided for @channels_standardPublicPsk. + /// + /// In en, this message translates to: + /// **'Standard public PSK'** + String get channels_standardPublicPsk; + + /// No description provided for @channels_pskHex. + /// + /// In en, this message translates to: + /// **'PSK (Hex)'** + String get channels_pskHex; + + /// No description provided for @channels_generateRandomPsk. + /// + /// In en, this message translates to: + /// **'Generate random PSK'** + String get channels_generateRandomPsk; + + /// No description provided for @channels_enterChannelName. + /// + /// In en, this message translates to: + /// **'Please enter a channel name'** + String get channels_enterChannelName; + + /// No description provided for @channels_pskMustBe32Hex. + /// + /// In en, this message translates to: + /// **'PSK must be 32 hex characters'** + String get channels_pskMustBe32Hex; + + /// No description provided for @channels_channelAdded. + /// + /// In en, this message translates to: + /// **'Channel \"{name}\" added'** + String channels_channelAdded(String name); + + /// No description provided for @channels_editChannelTitle. + /// + /// In en, this message translates to: + /// **'Edit Channel {index}'** + String channels_editChannelTitle(int index); + + /// No description provided for @channels_smazCompression. + /// + /// In en, this message translates to: + /// **'SMAZ compression'** + String get channels_smazCompression; + + /// No description provided for @channels_channelUpdated. + /// + /// In en, this message translates to: + /// **'Channel \"{name}\" updated'** + String channels_channelUpdated(String name); + + /// No description provided for @channels_publicChannelAdded. + /// + /// In en, this message translates to: + /// **'Public channel added'** + String get channels_publicChannelAdded; + + /// No description provided for @channels_sortBy. + /// + /// In en, this message translates to: + /// **'Sort by'** + String get channels_sortBy; + + /// No description provided for @channels_sortManual. + /// + /// In en, this message translates to: + /// **'Manual'** + String get channels_sortManual; + + /// No description provided for @channels_sortAZ. + /// + /// In en, this message translates to: + /// **'A-Z'** + String get channels_sortAZ; + + /// No description provided for @channels_sortLatestMessages. + /// + /// In en, this message translates to: + /// **'Latest messages'** + String get channels_sortLatestMessages; + + /// No description provided for @channels_sortUnread. + /// + /// In en, this message translates to: + /// **'Unread'** + String get channels_sortUnread; + + /// No description provided for @chat_noMessages. + /// + /// In en, this message translates to: + /// **'No messages yet'** + String get chat_noMessages; + + /// No description provided for @chat_sendMessageToStart. + /// + /// In en, this message translates to: + /// **'Send a message to get started'** + String get chat_sendMessageToStart; + + /// No description provided for @chat_originalMessageNotFound. + /// + /// In en, this message translates to: + /// **'Original message not found'** + String get chat_originalMessageNotFound; + + /// No description provided for @chat_replyingTo. + /// + /// In en, this message translates to: + /// **'Replying to {name}'** + String chat_replyingTo(String name); + + /// No description provided for @chat_replyTo. + /// + /// In en, this message translates to: + /// **'Reply to {name}'** + String chat_replyTo(String name); + + /// No description provided for @chat_location. + /// + /// In en, this message translates to: + /// **'Location'** + String get chat_location; + + /// No description provided for @chat_sendMessageTo. + /// + /// In en, this message translates to: + /// **'Send a message to {contactName}'** + String chat_sendMessageTo(String contactName); + + /// No description provided for @chat_typeMessage. + /// + /// In en, this message translates to: + /// **'Type a message...'** + String get chat_typeMessage; + + /// No description provided for @chat_messageTooLong. + /// + /// In en, this message translates to: + /// **'Message too long (max {maxBytes} bytes).'** + String chat_messageTooLong(int maxBytes); + + /// No description provided for @chat_messageCopied. + /// + /// In en, this message translates to: + /// **'Message copied'** + String get chat_messageCopied; + + /// No description provided for @chat_messageDeleted. + /// + /// In en, this message translates to: + /// **'Message deleted'** + String get chat_messageDeleted; + + /// No description provided for @chat_retryingMessage. + /// + /// In en, this message translates to: + /// **'Retrying message'** + String get chat_retryingMessage; + + /// No description provided for @chat_retryCount. + /// + /// In en, this message translates to: + /// **'Retry {current}/{max}'** + String chat_retryCount(int current, int max); + + /// No description provided for @chat_sendGif. + /// + /// In en, this message translates to: + /// **'Send GIF'** + String get chat_sendGif; + + /// No description provided for @chat_reply. + /// + /// In en, this message translates to: + /// **'Reply'** + String get chat_reply; + + /// No description provided for @chat_addReaction. + /// + /// In en, this message translates to: + /// **'Add Reaction'** + String get chat_addReaction; + + /// No description provided for @chat_me. + /// + /// In en, this message translates to: + /// **'Me'** + String get chat_me; + + /// No description provided for @emojiCategorySmileys. + /// + /// In en, this message translates to: + /// **'Smileys'** + String get emojiCategorySmileys; + + /// No description provided for @emojiCategoryGestures. + /// + /// In en, this message translates to: + /// **'Gestures'** + String get emojiCategoryGestures; + + /// No description provided for @emojiCategoryHearts. + /// + /// In en, this message translates to: + /// **'Hearts'** + String get emojiCategoryHearts; + + /// No description provided for @emojiCategoryObjects. + /// + /// In en, this message translates to: + /// **'Objects'** + String get emojiCategoryObjects; + + /// No description provided for @gifPicker_title. + /// + /// In en, this message translates to: + /// **'Choose a GIF'** + String get gifPicker_title; + + /// No description provided for @gifPicker_searchHint. + /// + /// In en, this message translates to: + /// **'Search GIFs...'** + String get gifPicker_searchHint; + + /// No description provided for @gifPicker_poweredBy. + /// + /// In en, this message translates to: + /// **'Powered by GIPHY'** + String get gifPicker_poweredBy; + + /// No description provided for @gifPicker_noGifsFound. + /// + /// In en, this message translates to: + /// **'No GIFs found'** + String get gifPicker_noGifsFound; + + /// No description provided for @gifPicker_failedLoad. + /// + /// In en, this message translates to: + /// **'Failed to load GIFs'** + String get gifPicker_failedLoad; + + /// No description provided for @gifPicker_failedSearch. + /// + /// In en, this message translates to: + /// **'Failed to search GIFs'** + String get gifPicker_failedSearch; + + /// No description provided for @gifPicker_noInternet. + /// + /// In en, this message translates to: + /// **'No internet connection'** + String get gifPicker_noInternet; + + /// No description provided for @debugLog_appTitle. + /// + /// In en, this message translates to: + /// **'App Debug Log'** + String get debugLog_appTitle; + + /// No description provided for @debugLog_bleTitle. + /// + /// In en, this message translates to: + /// **'BLE Debug Log'** + String get debugLog_bleTitle; + + /// No description provided for @debugLog_copyLog. + /// + /// In en, this message translates to: + /// **'Copy log'** + String get debugLog_copyLog; + + /// No description provided for @debugLog_clearLog. + /// + /// In en, this message translates to: + /// **'Clear log'** + String get debugLog_clearLog; + + /// No description provided for @debugLog_copied. + /// + /// In en, this message translates to: + /// **'Debug log copied'** + String get debugLog_copied; + + /// No description provided for @debugLog_bleCopied. + /// + /// In en, this message translates to: + /// **'BLE log copied'** + String get debugLog_bleCopied; + + /// No description provided for @debugLog_noEntries. + /// + /// In en, this message translates to: + /// **'No debug logs yet'** + String get debugLog_noEntries; + + /// No description provided for @debugLog_enableInSettings. + /// + /// In en, this message translates to: + /// **'Enable app debug logging in settings'** + String get debugLog_enableInSettings; + + /// No description provided for @debugLog_frames. + /// + /// In en, this message translates to: + /// **'Frames'** + String get debugLog_frames; + + /// No description provided for @debugLog_rawLogRx. + /// + /// In en, this message translates to: + /// **'Raw Log-RX'** + String get debugLog_rawLogRx; + + /// No description provided for @debugLog_noBleActivity. + /// + /// In en, this message translates to: + /// **'No BLE activity yet'** + String get debugLog_noBleActivity; + + /// No description provided for @debugFrame_length. + /// + /// In en, this message translates to: + /// **'Frame Length: {count} bytes'** + String debugFrame_length(int count); + + /// No description provided for @debugFrame_command. + /// + /// In en, this message translates to: + /// **'Command: 0x{value}'** + String debugFrame_command(String value); + + /// No description provided for @debugFrame_textMessageHeader. + /// + /// In en, this message translates to: + /// **'Text Message Frame:'** + String get debugFrame_textMessageHeader; + + /// No description provided for @debugFrame_destinationPubKey. + /// + /// In en, this message translates to: + /// **'- Destination PubKey: {pubKey}'** + String debugFrame_destinationPubKey(String pubKey); + + /// No description provided for @debugFrame_timestamp. + /// + /// In en, this message translates to: + /// **'- Timestamp: {timestamp}'** + String debugFrame_timestamp(int timestamp); + + /// No description provided for @debugFrame_flags. + /// + /// In en, this message translates to: + /// **'- Flags: 0x{value}'** + String debugFrame_flags(String value); + + /// No description provided for @debugFrame_textType. + /// + /// In en, this message translates to: + /// **'- Text Type: {type} ({label})'** + String debugFrame_textType(int type, String label); + + /// No description provided for @debugFrame_textTypeCli. + /// + /// In en, this message translates to: + /// **'CLI'** + String get debugFrame_textTypeCli; + + /// No description provided for @debugFrame_textTypePlain. + /// + /// In en, this message translates to: + /// **'Plain'** + String get debugFrame_textTypePlain; + + /// No description provided for @debugFrame_text. + /// + /// In en, this message translates to: + /// **'- Text: \"{text}\"'** + String debugFrame_text(String text); + + /// No description provided for @debugFrame_hexDump. + /// + /// In en, this message translates to: + /// **'Hex Dump:'** + String get debugFrame_hexDump; + + /// No description provided for @chat_pathManagement. + /// + /// In en, this message translates to: + /// **'Path Management'** + String get chat_pathManagement; + + /// No description provided for @chat_routingMode. + /// + /// In en, this message translates to: + /// **'Routing mode'** + String get chat_routingMode; + + /// No description provided for @chat_autoUseSavedPath. + /// + /// In en, this message translates to: + /// **'Auto (use saved path)'** + String get chat_autoUseSavedPath; + + /// No description provided for @chat_forceFloodMode. + /// + /// In en, this message translates to: + /// **'Force Flood Mode'** + String get chat_forceFloodMode; + + /// No description provided for @chat_recentAckPaths. + /// + /// In en, this message translates to: + /// **'Recent ACK Paths (tap to use):'** + String get chat_recentAckPaths; + + /// No description provided for @chat_pathHistoryFull. + /// + /// In en, this message translates to: + /// **'Path history is full. Remove entries to add new ones.'** + String get chat_pathHistoryFull; + + /// No description provided for @chat_hopSingular. + /// + /// In en, this message translates to: + /// **'hop'** + String get chat_hopSingular; + + /// No description provided for @chat_hopPlural. + /// + /// In en, this message translates to: + /// **'hops'** + String get chat_hopPlural; + + /// No description provided for @chat_hopsCount. + /// + /// In en, this message translates to: + /// **'{count} {count, plural, =1{hop} other{hops}}'** + String chat_hopsCount(int count); + + /// No description provided for @chat_successes. + /// + /// In en, this message translates to: + /// **'successes'** + String get chat_successes; + + /// No description provided for @chat_removePath. + /// + /// In en, this message translates to: + /// **'Remove path'** + String get chat_removePath; + + /// No description provided for @chat_noPathHistoryYet. + /// + /// In en, this message translates to: + /// **'No path history yet.\nSend a message to discover paths.'** + String get chat_noPathHistoryYet; + + /// No description provided for @chat_pathActions. + /// + /// In en, this message translates to: + /// **'Path Actions:'** + String get chat_pathActions; + + /// No description provided for @chat_setCustomPath. + /// + /// In en, this message translates to: + /// **'Set Custom Path'** + String get chat_setCustomPath; + + /// No description provided for @chat_setCustomPathSubtitle. + /// + /// In en, this message translates to: + /// **'Manually specify routing path'** + String get chat_setCustomPathSubtitle; + + /// No description provided for @chat_clearPath. + /// + /// In en, this message translates to: + /// **'Clear Path'** + String get chat_clearPath; + + /// No description provided for @chat_clearPathSubtitle. + /// + /// In en, this message translates to: + /// **'Force rediscovery on next send'** + String get chat_clearPathSubtitle; + + /// No description provided for @chat_pathCleared. + /// + /// In en, this message translates to: + /// **'Path cleared. Next message will rediscover route.'** + String get chat_pathCleared; + + /// No description provided for @chat_floodModeSubtitle. + /// + /// In en, this message translates to: + /// **'Use routing toggle in app bar'** + String get chat_floodModeSubtitle; + + /// No description provided for @chat_floodModeEnabled. + /// + /// In en, this message translates to: + /// **'Flood mode enabled. Toggle back via routing icon in app bar.'** + String get chat_floodModeEnabled; + + /// No description provided for @chat_fullPath. + /// + /// In en, this message translates to: + /// **'Full Path'** + String get chat_fullPath; + + /// No description provided for @chat_pathDetailsNotAvailable. + /// + /// In en, this message translates to: + /// **'Path details not available yet. Try sending a message to refresh.'** + String get chat_pathDetailsNotAvailable; + + /// No description provided for @chat_pathSetHops. + /// + /// In en, this message translates to: + /// **'Path set: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}'** + String chat_pathSetHops(int hopCount, String status); + + /// No description provided for @chat_pathSavedLocally. + /// + /// In en, this message translates to: + /// **'Saved locally. Connect to sync.'** + String get chat_pathSavedLocally; + + /// No description provided for @chat_pathDeviceConfirmed. + /// + /// In en, this message translates to: + /// **'Device confirmed.'** + String get chat_pathDeviceConfirmed; + + /// No description provided for @chat_pathDeviceNotConfirmed. + /// + /// In en, this message translates to: + /// **'Device not confirmed yet.'** + String get chat_pathDeviceNotConfirmed; + + /// No description provided for @chat_type. + /// + /// In en, this message translates to: + /// **'Type'** + String get chat_type; + + /// No description provided for @chat_path. + /// + /// In en, this message translates to: + /// **'Path'** + String get chat_path; + + /// No description provided for @chat_publicKey. + /// + /// In en, this message translates to: + /// **'Public Key'** + String get chat_publicKey; + + /// No description provided for @chat_compressOutgoingMessages. + /// + /// In en, this message translates to: + /// **'Compress outgoing messages'** + String get chat_compressOutgoingMessages; + + /// No description provided for @chat_floodForced. + /// + /// In en, this message translates to: + /// **'Flood (forced)'** + String get chat_floodForced; + + /// No description provided for @chat_directForced. + /// + /// In en, this message translates to: + /// **'Direct (forced)'** + String get chat_directForced; + + /// No description provided for @chat_hopsForced. + /// + /// In en, this message translates to: + /// **'{count} hops (forced)'** + String chat_hopsForced(int count); + + /// No description provided for @chat_floodAuto. + /// + /// In en, this message translates to: + /// **'Flood (auto)'** + String get chat_floodAuto; + + /// No description provided for @chat_direct. + /// + /// In en, this message translates to: + /// **'Direct'** + String get chat_direct; + + /// No description provided for @chat_poiShared. + /// + /// In en, this message translates to: + /// **'POI Shared'** + String get chat_poiShared; + + /// No description provided for @chat_unread. + /// + /// In en, this message translates to: + /// **'Unread: {count}'** + String chat_unread(int count); + + /// No description provided for @map_title. + /// + /// In en, this message translates to: + /// **'Node Map'** + String get map_title; + + /// No description provided for @map_noNodesWithLocation. + /// + /// In en, this message translates to: + /// **'No nodes with location data'** + String get map_noNodesWithLocation; + + /// No description provided for @map_nodesNeedGps. + /// + /// In en, this message translates to: + /// **'Nodes need to share their GPS coordinates\nto appear on the map'** + String get map_nodesNeedGps; + + /// No description provided for @map_nodesCount. + /// + /// In en, this message translates to: + /// **'Nodes: {count}'** + String map_nodesCount(int count); + + /// No description provided for @map_pinsCount. + /// + /// In en, this message translates to: + /// **'Pins: {count}'** + String map_pinsCount(int count); + + /// No description provided for @map_chat. + /// + /// In en, this message translates to: + /// **'Chat'** + String get map_chat; + + /// No description provided for @map_repeater. + /// + /// In en, this message translates to: + /// **'Repeater'** + String get map_repeater; + + /// No description provided for @map_room. + /// + /// In en, this message translates to: + /// **'Room'** + String get map_room; + + /// No description provided for @map_sensor. + /// + /// In en, this message translates to: + /// **'Sensor'** + String get map_sensor; + + /// No description provided for @map_pinDm. + /// + /// In en, this message translates to: + /// **'Pin (DM)'** + String get map_pinDm; + + /// No description provided for @map_pinPrivate. + /// + /// In en, this message translates to: + /// **'Pin (Private)'** + String get map_pinPrivate; + + /// No description provided for @map_pinPublic. + /// + /// In en, this message translates to: + /// **'Pin (Public)'** + String get map_pinPublic; + + /// No description provided for @map_lastSeen. + /// + /// In en, this message translates to: + /// **'Last Seen'** + String get map_lastSeen; + + /// No description provided for @map_disconnectConfirm. + /// + /// In en, this message translates to: + /// **'Are you sure you want to disconnect from this device?'** + String get map_disconnectConfirm; + + /// No description provided for @map_from. + /// + /// In en, this message translates to: + /// **'From'** + String get map_from; + + /// No description provided for @map_source. + /// + /// In en, this message translates to: + /// **'Source'** + String get map_source; + + /// No description provided for @map_flags. + /// + /// In en, this message translates to: + /// **'Flags'** + String get map_flags; + + /// No description provided for @map_shareMarkerHere. + /// + /// In en, this message translates to: + /// **'Share marker here'** + String get map_shareMarkerHere; + + /// No description provided for @map_pinLabel. + /// + /// In en, this message translates to: + /// **'Pin label'** + String get map_pinLabel; + + /// No description provided for @map_label. + /// + /// In en, this message translates to: + /// **'Label'** + String get map_label; + + /// No description provided for @map_pointOfInterest. + /// + /// In en, this message translates to: + /// **'Point of interest'** + String get map_pointOfInterest; + + /// No description provided for @map_sendToContact. + /// + /// In en, this message translates to: + /// **'Send to contact'** + String get map_sendToContact; + + /// No description provided for @map_sendToChannel. + /// + /// In en, this message translates to: + /// **'Send to channel'** + String get map_sendToChannel; + + /// No description provided for @map_noChannelsAvailable. + /// + /// In en, this message translates to: + /// **'No channels available'** + String get map_noChannelsAvailable; + + /// No description provided for @map_publicLocationShare. + /// + /// In en, this message translates to: + /// **'Public location share'** + String get map_publicLocationShare; + + /// No description provided for @map_publicLocationShareConfirm. + /// + /// In en, this message translates to: + /// **'You are about to share a location in {channelLabel}. This channel is public and anyone with the PSK can see it.'** + String map_publicLocationShareConfirm(String channelLabel); + + /// No description provided for @map_connectToShareMarkers. + /// + /// In en, this message translates to: + /// **'Connect to a device to share markers'** + String get map_connectToShareMarkers; + + /// No description provided for @map_filterNodes. + /// + /// In en, this message translates to: + /// **'Filter Nodes'** + String get map_filterNodes; + + /// No description provided for @map_nodeTypes. + /// + /// In en, this message translates to: + /// **'Node Types'** + String get map_nodeTypes; + + /// No description provided for @map_chatNodes. + /// + /// In en, this message translates to: + /// **'Chat Nodes'** + String get map_chatNodes; + + /// No description provided for @map_repeaters. + /// + /// In en, this message translates to: + /// **'Repeaters'** + String get map_repeaters; + + /// No description provided for @map_otherNodes. + /// + /// In en, this message translates to: + /// **'Other Nodes'** + String get map_otherNodes; + + /// No description provided for @map_keyPrefix. + /// + /// In en, this message translates to: + /// **'Key Prefix'** + String get map_keyPrefix; + + /// No description provided for @map_filterByKeyPrefix. + /// + /// In en, this message translates to: + /// **'Filter by key prefix'** + String get map_filterByKeyPrefix; + + /// No description provided for @map_publicKeyPrefix. + /// + /// In en, this message translates to: + /// **'Public key prefix'** + String get map_publicKeyPrefix; + + /// No description provided for @map_markers. + /// + /// In en, this message translates to: + /// **'Markers'** + String get map_markers; + + /// No description provided for @map_showSharedMarkers. + /// + /// In en, this message translates to: + /// **'Show shared markers'** + String get map_showSharedMarkers; + + /// No description provided for @map_lastSeenTime. + /// + /// In en, this message translates to: + /// **'Last Seen Time'** + String get map_lastSeenTime; + + /// No description provided for @map_sharedPin. + /// + /// In en, this message translates to: + /// **'Shared pin'** + String get map_sharedPin; + + /// No description provided for @map_joinRoom. + /// + /// In en, this message translates to: + /// **'Join Room'** + String get map_joinRoom; + + /// No description provided for @map_manageRepeater. + /// + /// In en, this message translates to: + /// **'Manage Repeater'** + String get map_manageRepeater; + + /// No description provided for @mapCache_title. + /// + /// In en, this message translates to: + /// **'Offline Map Cache'** + String get mapCache_title; + + /// No description provided for @mapCache_selectAreaFirst. + /// + /// In en, this message translates to: + /// **'Select an area to cache first'** + String get mapCache_selectAreaFirst; + + /// No description provided for @mapCache_noTilesToDownload. + /// + /// In en, this message translates to: + /// **'No tiles to download for this area'** + String get mapCache_noTilesToDownload; + + /// No description provided for @mapCache_downloadTilesTitle. + /// + /// In en, this message translates to: + /// **'Download tiles'** + String get mapCache_downloadTilesTitle; + + /// No description provided for @mapCache_downloadTilesPrompt. + /// + /// In en, this message translates to: + /// **'Download {count} tiles for offline use?'** + String mapCache_downloadTilesPrompt(int count); + + /// No description provided for @mapCache_downloadAction. + /// + /// In en, this message translates to: + /// **'Download'** + String get mapCache_downloadAction; + + /// No description provided for @mapCache_cachedTiles. + /// + /// In en, this message translates to: + /// **'Cached {count} tiles'** + String mapCache_cachedTiles(int count); + + /// No description provided for @mapCache_cachedTilesWithFailed. + /// + /// In en, this message translates to: + /// **'Cached {downloaded} tiles ({failed} failed)'** + String mapCache_cachedTilesWithFailed(int downloaded, int failed); + + /// No description provided for @mapCache_clearOfflineCacheTitle. + /// + /// In en, this message translates to: + /// **'Clear offline cache'** + String get mapCache_clearOfflineCacheTitle; + + /// No description provided for @mapCache_clearOfflineCachePrompt. + /// + /// In en, this message translates to: + /// **'Remove all cached map tiles?'** + String get mapCache_clearOfflineCachePrompt; + + /// No description provided for @mapCache_offlineCacheCleared. + /// + /// In en, this message translates to: + /// **'Offline cache cleared'** + String get mapCache_offlineCacheCleared; + + /// No description provided for @mapCache_noAreaSelected. + /// + /// In en, this message translates to: + /// **'No area selected'** + String get mapCache_noAreaSelected; + + /// No description provided for @mapCache_cacheArea. + /// + /// In en, this message translates to: + /// **'Cache Area'** + String get mapCache_cacheArea; + + /// No description provided for @mapCache_useCurrentView. + /// + /// In en, this message translates to: + /// **'Use Current View'** + String get mapCache_useCurrentView; + + /// No description provided for @mapCache_zoomRange. + /// + /// In en, this message translates to: + /// **'Zoom Range'** + String get mapCache_zoomRange; + + /// No description provided for @mapCache_estimatedTiles. + /// + /// In en, this message translates to: + /// **'Estimated tiles: {count}'** + String mapCache_estimatedTiles(int count); + + /// No description provided for @mapCache_downloadedTiles. + /// + /// In en, this message translates to: + /// **'Downloaded {completed} / {total}'** + String mapCache_downloadedTiles(int completed, int total); + + /// No description provided for @mapCache_downloadTilesButton. + /// + /// In en, this message translates to: + /// **'Download Tiles'** + String get mapCache_downloadTilesButton; + + /// No description provided for @mapCache_clearCacheButton. + /// + /// In en, this message translates to: + /// **'Clear Cache'** + String get mapCache_clearCacheButton; + + /// No description provided for @mapCache_failedDownloads. + /// + /// In en, this message translates to: + /// **'Failed downloads: {count}'** + String mapCache_failedDownloads(int count); + + /// No description provided for @mapCache_boundsLabel. + /// + /// In en, this message translates to: + /// **'N {north}, S {south}, E {east}, W {west}'** + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ); + + /// No description provided for @time_justNow. + /// + /// In en, this message translates to: + /// **'Just now'** + String get time_justNow; + + /// No description provided for @time_minutesAgo. + /// + /// In en, this message translates to: + /// **'{minutes}m ago'** + String time_minutesAgo(int minutes); + + /// No description provided for @time_hoursAgo. + /// + /// In en, this message translates to: + /// **'{hours}h ago'** + String time_hoursAgo(int hours); + + /// No description provided for @time_daysAgo. + /// + /// In en, this message translates to: + /// **'{days}d ago'** + String time_daysAgo(int days); + + /// No description provided for @time_hour. + /// + /// In en, this message translates to: + /// **'hour'** + String get time_hour; + + /// No description provided for @time_hours. + /// + /// In en, this message translates to: + /// **'hours'** + String get time_hours; + + /// No description provided for @time_day. + /// + /// In en, this message translates to: + /// **'day'** + String get time_day; + + /// No description provided for @time_days. + /// + /// In en, this message translates to: + /// **'days'** + String get time_days; + + /// No description provided for @time_week. + /// + /// In en, this message translates to: + /// **'week'** + String get time_week; + + /// No description provided for @time_weeks. + /// + /// In en, this message translates to: + /// **'weeks'** + String get time_weeks; + + /// No description provided for @time_month. + /// + /// In en, this message translates to: + /// **'month'** + String get time_month; + + /// No description provided for @time_months. + /// + /// In en, this message translates to: + /// **'months'** + String get time_months; + + /// No description provided for @time_minutes. + /// + /// In en, this message translates to: + /// **'minutes'** + String get time_minutes; + + /// No description provided for @time_allTime. + /// + /// In en, this message translates to: + /// **'All Time'** + String get time_allTime; + + /// No description provided for @dialog_disconnect. + /// + /// In en, this message translates to: + /// **'Disconnect'** + String get dialog_disconnect; + + /// No description provided for @dialog_disconnectConfirm. + /// + /// In en, this message translates to: + /// **'Are you sure you want to disconnect from this device?'** + String get dialog_disconnectConfirm; + + /// No description provided for @login_repeaterLogin. + /// + /// In en, this message translates to: + /// **'Repeater Login'** + String get login_repeaterLogin; + + /// No description provided for @login_roomLogin. + /// + /// In en, this message translates to: + /// **'Room Login'** + String get login_roomLogin; + + /// No description provided for @login_password. + /// + /// In en, this message translates to: + /// **'Password'** + String get login_password; + + /// No description provided for @login_enterPassword. + /// + /// In en, this message translates to: + /// **'Enter password'** + String get login_enterPassword; + + /// No description provided for @login_savePassword. + /// + /// In en, this message translates to: + /// **'Save password'** + String get login_savePassword; + + /// No description provided for @login_savePasswordSubtitle. + /// + /// In en, this message translates to: + /// **'Password will be stored securely on this device'** + String get login_savePasswordSubtitle; + + /// No description provided for @login_repeaterDescription. + /// + /// In en, this message translates to: + /// **'Enter the repeater password to access settings and status.'** + String get login_repeaterDescription; + + /// No description provided for @login_roomDescription. + /// + /// In en, this message translates to: + /// **'Enter the room password to access settings and status.'** + String get login_roomDescription; + + /// No description provided for @login_routing. + /// + /// In en, this message translates to: + /// **'Routing'** + String get login_routing; + + /// No description provided for @login_routingMode. + /// + /// In en, this message translates to: + /// **'Routing mode'** + String get login_routingMode; + + /// No description provided for @login_autoUseSavedPath. + /// + /// In en, this message translates to: + /// **'Auto (use saved path)'** + String get login_autoUseSavedPath; + + /// No description provided for @login_forceFloodMode. + /// + /// In en, this message translates to: + /// **'Force Flood Mode'** + String get login_forceFloodMode; + + /// No description provided for @login_managePaths. + /// + /// In en, this message translates to: + /// **'Manage Paths'** + String get login_managePaths; + + /// No description provided for @login_login. + /// + /// In en, this message translates to: + /// **'Login'** + String get login_login; + + /// No description provided for @login_attempt. + /// + /// In en, this message translates to: + /// **'Attempt {current}/{max}'** + String login_attempt(int current, int max); + + /// No description provided for @login_failed. + /// + /// In en, this message translates to: + /// **'Login failed: {error}'** + String login_failed(String error); + + /// No description provided for @common_reload. + /// + /// In en, this message translates to: + /// **'Reload'** + String get common_reload; + + /// No description provided for @common_clear. + /// + /// In en, this message translates to: + /// **'Clear'** + String get common_clear; + + /// No description provided for @path_currentPath. + /// + /// In en, this message translates to: + /// **'Current path: {path}'** + String path_currentPath(String path); + + /// No description provided for @path_usingHopsPath. + /// + /// In en, this message translates to: + /// **'Using {count} {count, plural, =1{hop} other{hops}} path'** + String path_usingHopsPath(int count); + + /// No description provided for @path_enterCustomPath. + /// + /// In en, this message translates to: + /// **'Enter Custom Path'** + String get path_enterCustomPath; + + /// No description provided for @path_currentPathLabel. + /// + /// In en, this message translates to: + /// **'Current path'** + String get path_currentPathLabel; + + /// No description provided for @path_hexPrefixInstructions. + /// + /// In en, this message translates to: + /// **'Enter 2-character hex prefixes for each hop, separated by commas.'** + String get path_hexPrefixInstructions; + + /// No description provided for @path_hexPrefixExample. + /// + /// In en, this message translates to: + /// **'Example: A1,F2,3C (each node uses first byte of its public key)'** + String get path_hexPrefixExample; + + /// No description provided for @path_labelHexPrefixes. + /// + /// In en, this message translates to: + /// **'Path (hex prefixes)'** + String get path_labelHexPrefixes; + + /// No description provided for @path_helperMaxHops. + /// + /// In en, this message translates to: + /// **'Max 64 hops. Each prefix is 2 hex characters (1 byte)'** + String get path_helperMaxHops; + + /// No description provided for @path_selectFromContacts. + /// + /// In en, this message translates to: + /// **'Or select from contacts:'** + String get path_selectFromContacts; + + /// No description provided for @path_noRepeatersFound. + /// + /// In en, this message translates to: + /// **'No repeaters or room servers found.'** + String get path_noRepeatersFound; + + /// No description provided for @path_customPathsRequire. + /// + /// In en, this message translates to: + /// **'Custom paths require intermediate hops that can relay messages.'** + String get path_customPathsRequire; + + /// No description provided for @path_invalidHexPrefixes. + /// + /// In en, this message translates to: + /// **'Invalid hex prefixes: {prefixes}'** + String path_invalidHexPrefixes(String prefixes); + + /// No description provided for @path_tooLong. + /// + /// In en, this message translates to: + /// **'Path too long. Maximum 64 hops allowed.'** + String get path_tooLong; + + /// No description provided for @path_setPath. + /// + /// In en, this message translates to: + /// **'Set Path'** + String get path_setPath; + + /// No description provided for @repeater_management. + /// + /// In en, this message translates to: + /// **'Repeater Management'** + String get repeater_management; + + /// No description provided for @repeater_managementTools. + /// + /// In en, this message translates to: + /// **'Management Tools'** + String get repeater_managementTools; + + /// No description provided for @repeater_status. + /// + /// In en, this message translates to: + /// **'Status'** + String get repeater_status; + + /// No description provided for @repeater_statusSubtitle. + /// + /// In en, this message translates to: + /// **'View repeater status, stats, and neighbors'** + String get repeater_statusSubtitle; + + /// No description provided for @repeater_telemetry. + /// + /// In en, this message translates to: + /// **'Telemetry'** + String get repeater_telemetry; + + /// No description provided for @repeater_telemetrySubtitle. + /// + /// In en, this message translates to: + /// **'View telemetry of sensors and system stats'** + String get repeater_telemetrySubtitle; + + /// No description provided for @repeater_cli. + /// + /// In en, this message translates to: + /// **'CLI'** + String get repeater_cli; + + /// No description provided for @repeater_cliSubtitle. + /// + /// In en, this message translates to: + /// **'Send commands to the repeater'** + String get repeater_cliSubtitle; + + /// No description provided for @repeater_settings. + /// + /// In en, this message translates to: + /// **'Settings'** + String get repeater_settings; + + /// No description provided for @repeater_settingsSubtitle. + /// + /// In en, this message translates to: + /// **'Configure repeater parameters'** + String get repeater_settingsSubtitle; + + /// No description provided for @repeater_statusTitle. + /// + /// In en, this message translates to: + /// **'Repeater Status'** + String get repeater_statusTitle; + + /// No description provided for @repeater_routingMode. + /// + /// In en, this message translates to: + /// **'Routing mode'** + String get repeater_routingMode; + + /// No description provided for @repeater_autoUseSavedPath. + /// + /// In en, this message translates to: + /// **'Auto (use saved path)'** + String get repeater_autoUseSavedPath; + + /// No description provided for @repeater_forceFloodMode. + /// + /// In en, this message translates to: + /// **'Force Flood Mode'** + String get repeater_forceFloodMode; + + /// No description provided for @repeater_pathManagement. + /// + /// In en, this message translates to: + /// **'Path management'** + String get repeater_pathManagement; + + /// No description provided for @repeater_refresh. + /// + /// In en, this message translates to: + /// **'Refresh'** + String get repeater_refresh; + + /// No description provided for @repeater_statusRequestTimeout. + /// + /// In en, this message translates to: + /// **'Status request timed out.'** + String get repeater_statusRequestTimeout; + + /// No description provided for @repeater_errorLoadingStatus. + /// + /// In en, this message translates to: + /// **'Error loading status: {error}'** + String repeater_errorLoadingStatus(String error); + + /// No description provided for @repeater_systemInformation. + /// + /// In en, this message translates to: + /// **'System Information'** + String get repeater_systemInformation; + + /// No description provided for @repeater_battery. + /// + /// In en, this message translates to: + /// **'Battery'** + String get repeater_battery; + + /// No description provided for @repeater_clockAtLogin. + /// + /// In en, this message translates to: + /// **'Clock (at login)'** + String get repeater_clockAtLogin; + + /// No description provided for @repeater_uptime. + /// + /// In en, this message translates to: + /// **'Uptime'** + String get repeater_uptime; + + /// No description provided for @repeater_queueLength. + /// + /// In en, this message translates to: + /// **'Queue Length'** + String get repeater_queueLength; + + /// No description provided for @repeater_debugFlags. + /// + /// In en, this message translates to: + /// **'Debug Flags'** + String get repeater_debugFlags; + + /// No description provided for @repeater_radioStatistics. + /// + /// In en, this message translates to: + /// **'Radio Statistics'** + String get repeater_radioStatistics; + + /// No description provided for @repeater_lastRssi. + /// + /// In en, this message translates to: + /// **'Last RSSI'** + String get repeater_lastRssi; + + /// No description provided for @repeater_lastSnr. + /// + /// In en, this message translates to: + /// **'Last SNR'** + String get repeater_lastSnr; + + /// No description provided for @repeater_noiseFloor. + /// + /// In en, this message translates to: + /// **'Noise Floor'** + String get repeater_noiseFloor; + + /// No description provided for @repeater_txAirtime. + /// + /// In en, this message translates to: + /// **'TX Airtime'** + String get repeater_txAirtime; + + /// No description provided for @repeater_rxAirtime. + /// + /// In en, this message translates to: + /// **'RX Airtime'** + String get repeater_rxAirtime; + + /// No description provided for @repeater_packetStatistics. + /// + /// In en, this message translates to: + /// **'Packet Statistics'** + String get repeater_packetStatistics; + + /// No description provided for @repeater_sent. + /// + /// In en, this message translates to: + /// **'Sent'** + String get repeater_sent; + + /// No description provided for @repeater_received. + /// + /// In en, this message translates to: + /// **'Received'** + String get repeater_received; + + /// No description provided for @repeater_duplicates. + /// + /// In en, this message translates to: + /// **'Duplicates'** + String get repeater_duplicates; + + /// No description provided for @repeater_daysHoursMinsSecs. + /// + /// In en, this message translates to: + /// **'{days} days {hours}h {minutes}m {seconds}s'** + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ); + + /// No description provided for @repeater_packetTxTotal. + /// + /// In en, this message translates to: + /// **'Total: {total}, Flood: {flood}, Direct: {direct}'** + String repeater_packetTxTotal(int total, String flood, String direct); + + /// No description provided for @repeater_packetRxTotal. + /// + /// In en, this message translates to: + /// **'Total: {total}, Flood: {flood}, Direct: {direct}'** + String repeater_packetRxTotal(int total, String flood, String direct); + + /// No description provided for @repeater_duplicatesFloodDirect. + /// + /// In en, this message translates to: + /// **'Flood: {flood}, Direct: {direct}'** + String repeater_duplicatesFloodDirect(String flood, String direct); + + /// No description provided for @repeater_duplicatesTotal. + /// + /// In en, this message translates to: + /// **'Total: {total}'** + String repeater_duplicatesTotal(int total); + + /// No description provided for @repeater_settingsTitle. + /// + /// In en, this message translates to: + /// **'Repeater Settings'** + String get repeater_settingsTitle; + + /// No description provided for @repeater_basicSettings. + /// + /// In en, this message translates to: + /// **'Basic Settings'** + String get repeater_basicSettings; + + /// No description provided for @repeater_repeaterName. + /// + /// In en, this message translates to: + /// **'Repeater Name'** + String get repeater_repeaterName; + + /// No description provided for @repeater_repeaterNameHelper. + /// + /// In en, this message translates to: + /// **'Display name for this repeater'** + String get repeater_repeaterNameHelper; + + /// No description provided for @repeater_adminPassword. + /// + /// In en, this message translates to: + /// **'Admin Password'** + String get repeater_adminPassword; + + /// No description provided for @repeater_adminPasswordHelper. + /// + /// In en, this message translates to: + /// **'Full access password'** + String get repeater_adminPasswordHelper; + + /// No description provided for @repeater_guestPassword. + /// + /// In en, this message translates to: + /// **'Guest Password'** + String get repeater_guestPassword; + + /// No description provided for @repeater_guestPasswordHelper. + /// + /// In en, this message translates to: + /// **'Read-only access password'** + String get repeater_guestPasswordHelper; + + /// No description provided for @repeater_radioSettings. + /// + /// In en, this message translates to: + /// **'Radio Settings'** + String get repeater_radioSettings; + + /// No description provided for @repeater_frequencyMhz. + /// + /// In en, this message translates to: + /// **'Frequency (MHz)'** + String get repeater_frequencyMhz; + + /// No description provided for @repeater_frequencyHelper. + /// + /// In en, this message translates to: + /// **'300-2500 MHz'** + String get repeater_frequencyHelper; + + /// No description provided for @repeater_txPower. + /// + /// In en, this message translates to: + /// **'TX Power'** + String get repeater_txPower; + + /// No description provided for @repeater_txPowerHelper. + /// + /// In en, this message translates to: + /// **'1-30 dBm'** + String get repeater_txPowerHelper; + + /// No description provided for @repeater_bandwidth. + /// + /// In en, this message translates to: + /// **'Bandwidth'** + String get repeater_bandwidth; + + /// No description provided for @repeater_spreadingFactor. + /// + /// In en, this message translates to: + /// **'Spreading Factor'** + String get repeater_spreadingFactor; + + /// No description provided for @repeater_codingRate. + /// + /// In en, this message translates to: + /// **'Coding Rate'** + String get repeater_codingRate; + + /// No description provided for @repeater_locationSettings. + /// + /// In en, this message translates to: + /// **'Location Settings'** + String get repeater_locationSettings; + + /// No description provided for @repeater_latitude. + /// + /// In en, this message translates to: + /// **'Latitude'** + String get repeater_latitude; + + /// No description provided for @repeater_latitudeHelper. + /// + /// In en, this message translates to: + /// **'Decimal degrees (e.g., 37.7749)'** + String get repeater_latitudeHelper; + + /// No description provided for @repeater_longitude. + /// + /// In en, this message translates to: + /// **'Longitude'** + String get repeater_longitude; + + /// No description provided for @repeater_longitudeHelper. + /// + /// In en, this message translates to: + /// **'Decimal degrees (e.g., -122.4194)'** + String get repeater_longitudeHelper; + + /// No description provided for @repeater_features. + /// + /// In en, this message translates to: + /// **'Features'** + String get repeater_features; + + /// No description provided for @repeater_packetForwarding. + /// + /// In en, this message translates to: + /// **'Packet Forwarding'** + String get repeater_packetForwarding; + + /// No description provided for @repeater_packetForwardingSubtitle. + /// + /// In en, this message translates to: + /// **'Enable repeater to forward packets'** + String get repeater_packetForwardingSubtitle; + + /// No description provided for @repeater_guestAccess. + /// + /// In en, this message translates to: + /// **'Guest Access'** + String get repeater_guestAccess; + + /// No description provided for @repeater_guestAccessSubtitle. + /// + /// In en, this message translates to: + /// **'Allow read-only guest access'** + String get repeater_guestAccessSubtitle; + + /// No description provided for @repeater_privacyMode. + /// + /// In en, this message translates to: + /// **'Privacy Mode'** + String get repeater_privacyMode; + + /// No description provided for @repeater_privacyModeSubtitle. + /// + /// In en, this message translates to: + /// **'Hide name/location in advertisements'** + String get repeater_privacyModeSubtitle; + + /// No description provided for @repeater_advertisementSettings. + /// + /// In en, this message translates to: + /// **'Advertisement Settings'** + String get repeater_advertisementSettings; + + /// No description provided for @repeater_localAdvertInterval. + /// + /// In en, this message translates to: + /// **'Local Advertisement Interval'** + String get repeater_localAdvertInterval; + + /// No description provided for @repeater_localAdvertIntervalMinutes. + /// + /// In en, this message translates to: + /// **'{minutes} minutes'** + String repeater_localAdvertIntervalMinutes(int minutes); + + /// No description provided for @repeater_floodAdvertInterval. + /// + /// In en, this message translates to: + /// **'Flood Advertisement Interval'** + String get repeater_floodAdvertInterval; + + /// No description provided for @repeater_floodAdvertIntervalHours. + /// + /// In en, this message translates to: + /// **'{hours} hours'** + String repeater_floodAdvertIntervalHours(int hours); + + /// No description provided for @repeater_encryptedAdvertInterval. + /// + /// In en, this message translates to: + /// **'Encrypted Advertisement Interval'** + String get repeater_encryptedAdvertInterval; + + /// No description provided for @repeater_dangerZone. + /// + /// In en, this message translates to: + /// **'Danger Zone'** + String get repeater_dangerZone; + + /// No description provided for @repeater_rebootRepeater. + /// + /// In en, this message translates to: + /// **'Reboot Repeater'** + String get repeater_rebootRepeater; + + /// No description provided for @repeater_rebootRepeaterSubtitle. + /// + /// In en, this message translates to: + /// **'Restart the repeater device'** + String get repeater_rebootRepeaterSubtitle; + + /// No description provided for @repeater_rebootRepeaterConfirm. + /// + /// In en, this message translates to: + /// **'Are you sure you want to reboot this repeater?'** + String get repeater_rebootRepeaterConfirm; + + /// No description provided for @repeater_regenerateIdentityKey. + /// + /// In en, this message translates to: + /// **'Regenerate Identity Key'** + String get repeater_regenerateIdentityKey; + + /// No description provided for @repeater_regenerateIdentityKeySubtitle. + /// + /// In en, this message translates to: + /// **'Generate new public/private key pair'** + String get repeater_regenerateIdentityKeySubtitle; + + /// No description provided for @repeater_regenerateIdentityKeyConfirm. + /// + /// In en, this message translates to: + /// **'This will generate a new identity for the repeater. Continue?'** + String get repeater_regenerateIdentityKeyConfirm; + + /// No description provided for @repeater_eraseFileSystem. + /// + /// In en, this message translates to: + /// **'Erase File System'** + String get repeater_eraseFileSystem; + + /// No description provided for @repeater_eraseFileSystemSubtitle. + /// + /// In en, this message translates to: + /// **'Format the repeater file system'** + String get repeater_eraseFileSystemSubtitle; + + /// No description provided for @repeater_eraseFileSystemConfirm. + /// + /// In en, this message translates to: + /// **'WARNING: This will erase all data on the repeater. This cannot be undone!'** + String get repeater_eraseFileSystemConfirm; + + /// No description provided for @repeater_eraseSerialOnly. + /// + /// In en, this message translates to: + /// **'Erase is only available over serial console.'** + String get repeater_eraseSerialOnly; + + /// No description provided for @repeater_commandSent. + /// + /// In en, this message translates to: + /// **'Command sent: {command}'** + String repeater_commandSent(String command); + + /// No description provided for @repeater_errorSendingCommand. + /// + /// In en, this message translates to: + /// **'Error sending command: {error}'** + String repeater_errorSendingCommand(String error); + + /// No description provided for @repeater_confirm. + /// + /// In en, this message translates to: + /// **'Confirm'** + String get repeater_confirm; + + /// No description provided for @repeater_settingsSaved. + /// + /// In en, this message translates to: + /// **'Settings saved successfully'** + String get repeater_settingsSaved; + + /// No description provided for @repeater_errorSavingSettings. + /// + /// In en, this message translates to: + /// **'Error saving settings: {error}'** + String repeater_errorSavingSettings(String error); + + /// No description provided for @repeater_refreshBasicSettings. + /// + /// In en, this message translates to: + /// **'Refresh Basic Settings'** + String get repeater_refreshBasicSettings; + + /// No description provided for @repeater_refreshRadioSettings. + /// + /// In en, this message translates to: + /// **'Refresh Radio Settings'** + String get repeater_refreshRadioSettings; + + /// No description provided for @repeater_refreshTxPower. + /// + /// In en, this message translates to: + /// **'Refresh TX power'** + String get repeater_refreshTxPower; + + /// No description provided for @repeater_refreshLocationSettings. + /// + /// In en, this message translates to: + /// **'Refresh Location Settings'** + String get repeater_refreshLocationSettings; + + /// No description provided for @repeater_refreshPacketForwarding. + /// + /// In en, this message translates to: + /// **'Refresh Packet Forwarding'** + String get repeater_refreshPacketForwarding; + + /// No description provided for @repeater_refreshGuestAccess. + /// + /// In en, this message translates to: + /// **'Refresh Guest Access'** + String get repeater_refreshGuestAccess; + + /// No description provided for @repeater_refreshPrivacyMode. + /// + /// In en, this message translates to: + /// **'Refresh Privacy Mode'** + String get repeater_refreshPrivacyMode; + + /// No description provided for @repeater_refreshAdvertisementSettings. + /// + /// In en, this message translates to: + /// **'Refresh Advertisement Settings'** + String get repeater_refreshAdvertisementSettings; + + /// No description provided for @repeater_refreshed. + /// + /// In en, this message translates to: + /// **'{label} refreshed'** + String repeater_refreshed(String label); + + /// No description provided for @repeater_errorRefreshing. + /// + /// In en, this message translates to: + /// **'Error refreshing {label}'** + String repeater_errorRefreshing(String label); + + /// No description provided for @repeater_cliTitle. + /// + /// In en, this message translates to: + /// **'Repeater CLI'** + String get repeater_cliTitle; + + /// No description provided for @repeater_debugNextCommand. + /// + /// In en, this message translates to: + /// **'Debug Next Command'** + String get repeater_debugNextCommand; + + /// No description provided for @repeater_commandHelp. + /// + /// In en, this message translates to: + /// **'Command Help'** + String get repeater_commandHelp; + + /// No description provided for @repeater_clearHistory. + /// + /// In en, this message translates to: + /// **'Clear History'** + String get repeater_clearHistory; + + /// No description provided for @repeater_noCommandsSent. + /// + /// In en, this message translates to: + /// **'No commands sent yet'** + String get repeater_noCommandsSent; + + /// No description provided for @repeater_typeCommandOrUseQuick. + /// + /// In en, this message translates to: + /// **'Type a command below or use quick commands'** + String get repeater_typeCommandOrUseQuick; + + /// No description provided for @repeater_enterCommandHint. + /// + /// In en, this message translates to: + /// **'Enter command...'** + String get repeater_enterCommandHint; + + /// No description provided for @repeater_previousCommand. + /// + /// In en, this message translates to: + /// **'Previous command'** + String get repeater_previousCommand; + + /// No description provided for @repeater_nextCommand. + /// + /// In en, this message translates to: + /// **'Next command'** + String get repeater_nextCommand; + + /// No description provided for @repeater_enterCommandFirst. + /// + /// In en, this message translates to: + /// **'Enter a command first'** + String get repeater_enterCommandFirst; + + /// No description provided for @repeater_cliCommandFrameTitle. + /// + /// In en, this message translates to: + /// **'CLI Command Frame'** + String get repeater_cliCommandFrameTitle; + + /// No description provided for @repeater_cliCommandError. + /// + /// In en, this message translates to: + /// **'Error: {error}'** + String repeater_cliCommandError(String error); + + /// No description provided for @repeater_cliQuickGetName. + /// + /// In en, this message translates to: + /// **'Get Name'** + String get repeater_cliQuickGetName; + + /// No description provided for @repeater_cliQuickGetRadio. + /// + /// In en, this message translates to: + /// **'Get Radio'** + String get repeater_cliQuickGetRadio; + + /// No description provided for @repeater_cliQuickGetTx. + /// + /// In en, this message translates to: + /// **'Get TX'** + String get repeater_cliQuickGetTx; + + /// No description provided for @repeater_cliQuickNeighbors. + /// + /// In en, this message translates to: + /// **'Neighbors'** + String get repeater_cliQuickNeighbors; + + /// No description provided for @repeater_cliQuickVersion. + /// + /// In en, this message translates to: + /// **'Version'** + String get repeater_cliQuickVersion; + + /// No description provided for @repeater_cliQuickAdvertise. + /// + /// In en, this message translates to: + /// **'Advertise'** + String get repeater_cliQuickAdvertise; + + /// No description provided for @repeater_cliQuickClock. + /// + /// In en, this message translates to: + /// **'Clock'** + String get repeater_cliQuickClock; + + /// No description provided for @repeater_cliHelpAdvert. + /// + /// In en, this message translates to: + /// **'Sends an advertisement packet'** + String get repeater_cliHelpAdvert; + + /// No description provided for @repeater_cliHelpReboot. + /// + /// In en, this message translates to: + /// **'Reboots the device. (note, you\'ll prob get \'Timeout\' which is normal)'** + String get repeater_cliHelpReboot; + + /// No description provided for @repeater_cliHelpClock. + /// + /// In en, this message translates to: + /// **'Displays current time per device\'s clock.'** + String get repeater_cliHelpClock; + + /// No description provided for @repeater_cliHelpPassword. + /// + /// In en, this message translates to: + /// **'Sets a new admin password for the device.'** + String get repeater_cliHelpPassword; + + /// No description provided for @repeater_cliHelpVersion. + /// + /// In en, this message translates to: + /// **'Shows the device version and firmware build date.'** + String get repeater_cliHelpVersion; + + /// No description provided for @repeater_cliHelpClearStats. + /// + /// In en, this message translates to: + /// **'Resets various stats counters to zero.'** + String get repeater_cliHelpClearStats; + + /// No description provided for @repeater_cliHelpSetAf. + /// + /// In en, this message translates to: + /// **'Sets the air-time-factor.'** + String get repeater_cliHelpSetAf; + + /// No description provided for @repeater_cliHelpSetTx. + /// + /// In en, this message translates to: + /// **'Sets LoRa transmit power in dBm. (reboot to apply)'** + String get repeater_cliHelpSetTx; + + /// No description provided for @repeater_cliHelpSetRepeat. + /// + /// In en, this message translates to: + /// **'Enables or disables the repeater role for this node.'** + String get repeater_cliHelpSetRepeat; + + /// No description provided for @repeater_cliHelpSetAllowReadOnly. + /// + /// In en, this message translates to: + /// **'(Room server) If \'on\', then login in blank password will be allowed, but cannot Post to room. (just read only)'** + String get repeater_cliHelpSetAllowReadOnly; + + /// No description provided for @repeater_cliHelpSetFloodMax. + /// + /// In en, this message translates to: + /// **'Sets the maximum number of hops of inbound flood packet (if >= max, packet is not forwarded)'** + String get repeater_cliHelpSetFloodMax; + + /// No description provided for @repeater_cliHelpSetIntThresh. + /// + /// In en, this message translates to: + /// **'Sets the Interference Threshold (in DB). Default is 14. Set to 0 to disable channel interference detection.'** + String get repeater_cliHelpSetIntThresh; + + /// No description provided for @repeater_cliHelpSetAgcResetInterval. + /// + /// In en, this message translates to: + /// **'Sets the interval to reset the Auto Gain Controller. Set to 0 to disable.'** + String get repeater_cliHelpSetAgcResetInterval; + + /// No description provided for @repeater_cliHelpSetMultiAcks. + /// + /// In en, this message translates to: + /// **'Enables or disables the \'double ACKs\' feature.'** + String get repeater_cliHelpSetMultiAcks; + + /// No description provided for @repeater_cliHelpSetAdvertInterval. + /// + /// In en, this message translates to: + /// **'Sets the timer interval in minutes to send a local (zero-hop) advertisement packet. Set to 0 to disable.'** + String get repeater_cliHelpSetAdvertInterval; + + /// No description provided for @repeater_cliHelpSetFloodAdvertInterval. + /// + /// In en, this message translates to: + /// **'Sets the timer interval in hours to send a flood advertisement packet. Set to 0 to disable.'** + String get repeater_cliHelpSetFloodAdvertInterval; + + /// No description provided for @repeater_cliHelpSetGuestPassword. + /// + /// In en, this message translates to: + /// **'Sets/updates the guest password. (for repeaters, guest logins can send the \"Get Stats\" request)'** + String get repeater_cliHelpSetGuestPassword; + + /// No description provided for @repeater_cliHelpSetName. + /// + /// In en, this message translates to: + /// **'Sets the advertisement name.'** + String get repeater_cliHelpSetName; + + /// No description provided for @repeater_cliHelpSetLat. + /// + /// In en, this message translates to: + /// **'Sets the advertisement map latitude. (decimal degrees)'** + String get repeater_cliHelpSetLat; + + /// No description provided for @repeater_cliHelpSetLon. + /// + /// In en, this message translates to: + /// **'Sets the advertisement map longitude. (decimal degrees)'** + String get repeater_cliHelpSetLon; + + /// No description provided for @repeater_cliHelpSetRadio. + /// + /// In en, this message translates to: + /// **'Sets completely new radio params, and saves to preferences. Requires a \"reboot\" command to apply.'** + String get repeater_cliHelpSetRadio; + + /// No description provided for @repeater_cliHelpSetRxDelay. + /// + /// In en, this message translates to: + /// **'Sets (experimental) base (must be > 1 for effect) for applying slight delay to received packets, based on signal strength/score. Set to 0 to disable.'** + String get repeater_cliHelpSetRxDelay; + + /// No description provided for @repeater_cliHelpSetTxDelay. + /// + /// In en, this message translates to: + /// **'Sets a factor multiplied with time-on-air for a flood-mode packet and with a randomized slot system, to delay its forwarding. (to decrease likelihood of collisions)'** + String get repeater_cliHelpSetTxDelay; + + /// No description provided for @repeater_cliHelpSetDirectTxDelay. + /// + /// In en, this message translates to: + /// **'Same as txdelay, but for applying a random delay to the forwarding of direct-mode packets.'** + String get repeater_cliHelpSetDirectTxDelay; + + /// No description provided for @repeater_cliHelpSetBridgeEnabled. + /// + /// In en, this message translates to: + /// **'Enable/Disable bridge.'** + String get repeater_cliHelpSetBridgeEnabled; + + /// No description provided for @repeater_cliHelpSetBridgeDelay. + /// + /// In en, this message translates to: + /// **'Set delay before retransmitting packets.'** + String get repeater_cliHelpSetBridgeDelay; + + /// No description provided for @repeater_cliHelpSetBridgeSource. + /// + /// In en, this message translates to: + /// **'Choose wether the bridge will retransmit received packets or transmitted packets.'** + String get repeater_cliHelpSetBridgeSource; + + /// No description provided for @repeater_cliHelpSetBridgeBaud. + /// + /// In en, this message translates to: + /// **'Set serial link baudrate for rs232 bridges.'** + String get repeater_cliHelpSetBridgeBaud; + + /// No description provided for @repeater_cliHelpSetBridgeSecret. + /// + /// In en, this message translates to: + /// **'Set bridge secret for espnow bridges.'** + String get repeater_cliHelpSetBridgeSecret; + + /// No description provided for @repeater_cliHelpSetAdcMultiplier. + /// + /// In en, this message translates to: + /// **'Sets custom factor to adjust reported battery voltage (only supported on select boards).'** + String get repeater_cliHelpSetAdcMultiplier; + + /// No description provided for @repeater_cliHelpTempRadio. + /// + /// In en, this message translates to: + /// **'Sets temporary radio params for the given number of minutes, reverting to original radio params afterward. (does NOT save to preferences).'** + String get repeater_cliHelpTempRadio; + + /// No description provided for @repeater_cliHelpSetPerm. + /// + /// In en, this message translates to: + /// **'Modifies the ACL. Removes matching entry (by pubkey prefix) if \"permissions\" is zero. Adds new entry if pubkey-hex is full length and is not currently in ACL. Updates entry by matching pubkey prefix. Permission bits vary per firmware role, but low 2 bits are: 0 (Guest), 1 (Read only), 2 (Read write), 3 (Admin)'** + String get repeater_cliHelpSetPerm; + + /// No description provided for @repeater_cliHelpGetBridgeType. + /// + /// In en, this message translates to: + /// **'Gets bridge type none, rs232, espnow'** + String get repeater_cliHelpGetBridgeType; + + /// No description provided for @repeater_cliHelpLogStart. + /// + /// In en, this message translates to: + /// **'Starts packet logging to file system.'** + String get repeater_cliHelpLogStart; + + /// No description provided for @repeater_cliHelpLogStop. + /// + /// In en, this message translates to: + /// **'Stops packet logging to file system.'** + String get repeater_cliHelpLogStop; + + /// No description provided for @repeater_cliHelpLogErase. + /// + /// In en, this message translates to: + /// **'Erases the packet logs from file system.'** + String get repeater_cliHelpLogErase; + + /// No description provided for @repeater_cliHelpNeighbors. + /// + /// In en, this message translates to: + /// **'Shows a list of other repeater nodes heard via zero-hop adverts. Each line is id-prefix-hex:timestamp:snr-times-4'** + String get repeater_cliHelpNeighbors; + + /// No description provided for @repeater_cliHelpNeighborRemove. + /// + /// In en, this message translates to: + /// **'Removes first matching entry (by pubkey prefix (hex)), from neighbors list.'** + String get repeater_cliHelpNeighborRemove; + + /// No description provided for @repeater_cliHelpRegion. + /// + /// In en, this message translates to: + /// **'(serial only) Lists all defined regions and current flood permissions.'** + String get repeater_cliHelpRegion; + + /// No description provided for @repeater_cliHelpRegionLoad. + /// + /// In en, this message translates to: + /// **'NOTE: this is a special multi-command invocation. Each subsequent command is a region name (indented with spaces to indicate parent hierarchy, with one space at minimum). Terminated by sending a blank line/command.'** + String get repeater_cliHelpRegionLoad; + + /// No description provided for @repeater_cliHelpRegionGet. + /// + /// In en, this message translates to: + /// **'Searches for region with given name prefix (or \"*\" for the global scope). Replies with \"-> region-name (parent-name) \'F\'\"'** + String get repeater_cliHelpRegionGet; + + /// No description provided for @repeater_cliHelpRegionPut. + /// + /// In en, this message translates to: + /// **'Adds or updates a region definition with given name.'** + String get repeater_cliHelpRegionPut; + + /// No description provided for @repeater_cliHelpRegionRemove. + /// + /// In en, this message translates to: + /// **'Removes a region definition with given name. (must match exactly, and have no child regions)'** + String get repeater_cliHelpRegionRemove; + + /// No description provided for @repeater_cliHelpRegionAllowf. + /// + /// In en, this message translates to: + /// **'Sets the \'F\'lood permission for the given region. (\'*\' for the global/legacy scope)'** + String get repeater_cliHelpRegionAllowf; + + /// No description provided for @repeater_cliHelpRegionDenyf. + /// + /// In en, this message translates to: + /// **'Removes the \'F\'lood permission for the given region. (NOTE: at this stage NOT advised to use this on the global/legacy scope!!)'** + String get repeater_cliHelpRegionDenyf; + + /// No description provided for @repeater_cliHelpRegionHome. + /// + /// In en, this message translates to: + /// **'Replies with the current \'home\' region. (Note applied anywhere yet, reserved for future)'** + String get repeater_cliHelpRegionHome; + + /// No description provided for @repeater_cliHelpRegionHomeSet. + /// + /// In en, this message translates to: + /// **'Sets the \'home\' region.'** + String get repeater_cliHelpRegionHomeSet; + + /// No description provided for @repeater_cliHelpRegionSave. + /// + /// In en, this message translates to: + /// **'Persists the region list/map to storage.'** + String get repeater_cliHelpRegionSave; + + /// No description provided for @repeater_cliHelpGps. + /// + /// In en, this message translates to: + /// **'Gives status of gps. When gps is off, it replies only off, if on it replies with on, status, fix, sat count'** + String get repeater_cliHelpGps; + + /// No description provided for @repeater_cliHelpGpsOnOff. + /// + /// In en, this message translates to: + /// **'Toggles gps power state.'** + String get repeater_cliHelpGpsOnOff; + + /// No description provided for @repeater_cliHelpGpsSync. + /// + /// In en, this message translates to: + /// **'Syncs node time with gps clock.'** + String get repeater_cliHelpGpsSync; + + /// No description provided for @repeater_cliHelpGpsSetLoc. + /// + /// In en, this message translates to: + /// **'Sets node\'s position to gps coordinates and save preferences.'** + String get repeater_cliHelpGpsSetLoc; + + /// No description provided for @repeater_cliHelpGpsAdvert. + /// + /// In en, this message translates to: + /// **'Gives location advert configuration of the node:\n- none: don\'t include location in adverts\n- share: share gps location (from SensorManager)\n- prefs: advert the location stored in preferences'** + String get repeater_cliHelpGpsAdvert; + + /// No description provided for @repeater_cliHelpGpsAdvertSet. + /// + /// In en, this message translates to: + /// **'Sets location advert configuration.'** + String get repeater_cliHelpGpsAdvertSet; + + /// No description provided for @repeater_commandsListTitle. + /// + /// In en, this message translates to: + /// **'Commands List'** + String get repeater_commandsListTitle; + + /// No description provided for @repeater_commandsListNote. + /// + /// In en, this message translates to: + /// **'NOTE: for the various \"set ...\" commands, there is also a \"get ...\" command.'** + String get repeater_commandsListNote; + + /// No description provided for @repeater_general. + /// + /// In en, this message translates to: + /// **'General'** + String get repeater_general; + + /// No description provided for @repeater_settingsCategory. + /// + /// In en, this message translates to: + /// **'Settings'** + String get repeater_settingsCategory; + + /// No description provided for @repeater_bridge. + /// + /// In en, this message translates to: + /// **'Bridge'** + String get repeater_bridge; + + /// No description provided for @repeater_logging. + /// + /// In en, this message translates to: + /// **'Logging'** + String get repeater_logging; + + /// No description provided for @repeater_neighborsRepeaterOnly. + /// + /// In en, this message translates to: + /// **'Neighbors (Repeater only)'** + String get repeater_neighborsRepeaterOnly; + + /// No description provided for @repeater_regionManagementRepeaterOnly. + /// + /// In en, this message translates to: + /// **'Region Management (Repeater only)'** + String get repeater_regionManagementRepeaterOnly; + + /// No description provided for @repeater_regionNote. + /// + /// In en, this message translates to: + /// **'Region commands have been introduced to manage region definitions and permissions.'** + String get repeater_regionNote; + + /// No description provided for @repeater_gpsManagement. + /// + /// In en, this message translates to: + /// **'GPS Management'** + String get repeater_gpsManagement; + + /// No description provided for @repeater_gpsNote. + /// + /// In en, this message translates to: + /// **'gps command has been introduced to manage location related topics.'** + String get repeater_gpsNote; + + /// No description provided for @telemetry_receivedData. + /// + /// In en, this message translates to: + /// **'Received Telemetry Data'** + String get telemetry_receivedData; + + /// No description provided for @telemetry_requestTimeout. + /// + /// In en, this message translates to: + /// **'Telemetry request timed out.'** + String get telemetry_requestTimeout; + + /// No description provided for @telemetry_errorLoading. + /// + /// In en, this message translates to: + /// **'Error loading telemetry: {error}'** + String telemetry_errorLoading(String error); + + /// No description provided for @telemetry_noData. + /// + /// In en, this message translates to: + /// **'No telemetry data available.'** + String get telemetry_noData; + + /// No description provided for @telemetry_channelTitle. + /// + /// In en, this message translates to: + /// **'Channel {channel}'** + String telemetry_channelTitle(int channel); + + /// No description provided for @telemetry_batteryLabel. + /// + /// In en, this message translates to: + /// **'Battery'** + String get telemetry_batteryLabel; + + /// No description provided for @telemetry_voltageLabel. + /// + /// In en, this message translates to: + /// **'Voltage'** + String get telemetry_voltageLabel; + + /// No description provided for @telemetry_mcuTemperatureLabel. + /// + /// In en, this message translates to: + /// **'MCU Temperature'** + String get telemetry_mcuTemperatureLabel; + + /// No description provided for @telemetry_temperatureLabel. + /// + /// In en, this message translates to: + /// **'Temperature'** + String get telemetry_temperatureLabel; + + /// No description provided for @telemetry_currentLabel. + /// + /// In en, this message translates to: + /// **'Current'** + String get telemetry_currentLabel; + + /// No description provided for @telemetry_batteryValue. + /// + /// In en, this message translates to: + /// **'{percent}% / {volts}V'** + String telemetry_batteryValue(int percent, String volts); + + /// No description provided for @telemetry_voltageValue. + /// + /// In en, this message translates to: + /// **'{volts}V'** + String telemetry_voltageValue(String volts); + + /// No description provided for @telemetry_currentValue. + /// + /// In en, this message translates to: + /// **'{amps}A'** + String telemetry_currentValue(String amps); + + /// No description provided for @telemetry_temperatureValue. + /// + /// In en, this message translates to: + /// **'{celsius}°C / {fahrenheit}°F'** + String telemetry_temperatureValue(String celsius, String fahrenheit); + + /// No description provided for @channelPath_title. + /// + /// In en, this message translates to: + /// **'Packet Path'** + String get channelPath_title; + + /// No description provided for @channelPath_viewMap. + /// + /// In en, this message translates to: + /// **'View map'** + String get channelPath_viewMap; + + /// No description provided for @channelPath_otherObservedPaths. + /// + /// In en, this message translates to: + /// **'Other Observed Paths'** + String get channelPath_otherObservedPaths; + + /// No description provided for @channelPath_repeaterHops. + /// + /// In en, this message translates to: + /// **'Repeater Hops'** + String get channelPath_repeaterHops; + + /// No description provided for @channelPath_noHopDetails. + /// + /// In en, this message translates to: + /// **'Hop details are not provided for this packet.'** + String get channelPath_noHopDetails; + + /// No description provided for @channelPath_messageDetails. + /// + /// In en, this message translates to: + /// **'Message Details'** + String get channelPath_messageDetails; + + /// No description provided for @channelPath_senderLabel. + /// + /// In en, this message translates to: + /// **'Sender'** + String get channelPath_senderLabel; + + /// No description provided for @channelPath_timeLabel. + /// + /// In en, this message translates to: + /// **'Time'** + String get channelPath_timeLabel; + + /// No description provided for @channelPath_repeatsLabel. + /// + /// In en, this message translates to: + /// **'Repeats'** + String get channelPath_repeatsLabel; + + /// No description provided for @channelPath_pathLabel. + /// + /// In en, this message translates to: + /// **'Path {index}'** + String channelPath_pathLabel(int index); + + /// No description provided for @channelPath_observedLabel. + /// + /// In en, this message translates to: + /// **'Observed'** + String get channelPath_observedLabel; + + /// No description provided for @channelPath_observedPathTitle. + /// + /// In en, this message translates to: + /// **'Observed path {index} • {hops}'** + String channelPath_observedPathTitle(int index, String hops); + + /// No description provided for @channelPath_noLocationData. + /// + /// In en, this message translates to: + /// **'No location data'** + String get channelPath_noLocationData; + + /// No description provided for @channelPath_timeWithDate. + /// + /// In en, this message translates to: + /// **'{day}/{month} {time}'** + String channelPath_timeWithDate(int day, int month, String time); + + /// No description provided for @channelPath_timeOnly. + /// + /// In en, this message translates to: + /// **'{time}'** + String channelPath_timeOnly(String time); + + /// No description provided for @channelPath_unknownPath. + /// + /// In en, this message translates to: + /// **'Unknown'** + String get channelPath_unknownPath; + + /// No description provided for @channelPath_floodPath. + /// + /// In en, this message translates to: + /// **'Flood'** + String get channelPath_floodPath; + + /// No description provided for @channelPath_directPath. + /// + /// In en, this message translates to: + /// **'Direct'** + String get channelPath_directPath; + + /// No description provided for @channelPath_observedZeroOf. + /// + /// In en, this message translates to: + /// **'0 of {total} hops'** + String channelPath_observedZeroOf(int total); + + /// No description provided for @channelPath_observedSomeOf. + /// + /// In en, this message translates to: + /// **'{observed} of {total} hops'** + String channelPath_observedSomeOf(int observed, int total); + + /// No description provided for @channelPath_mapTitle. + /// + /// In en, this message translates to: + /// **'Path Map'** + String get channelPath_mapTitle; + + /// No description provided for @channelPath_noRepeaterLocations. + /// + /// In en, this message translates to: + /// **'No repeater locations available for this path.'** + String get channelPath_noRepeaterLocations; + + /// No description provided for @channelPath_primaryPath. + /// + /// In en, this message translates to: + /// **'Path {index} (Primary)'** + String channelPath_primaryPath(int index); + + /// No description provided for @channelPath_pathLabelTitle. + /// + /// In en, this message translates to: + /// **'Path'** + String get channelPath_pathLabelTitle; + + /// No description provided for @channelPath_observedPathHeader. + /// + /// In en, this message translates to: + /// **'Observed Path'** + String get channelPath_observedPathHeader; + + /// No description provided for @channelPath_selectedPathLabel. + /// + /// In en, this message translates to: + /// **'{label} • {prefixes}'** + String channelPath_selectedPathLabel(String label, String prefixes); + + /// No description provided for @channelPath_noHopDetailsAvailable. + /// + /// In en, this message translates to: + /// **'No hop details available for this packet.'** + String get channelPath_noHopDetailsAvailable; + + /// No description provided for @channelPath_unknownRepeater. + /// + /// In en, this message translates to: + /// **'Unknown Repeater'** + String get channelPath_unknownRepeater; + + /// No description provided for @listFilter_tooltip. + /// + /// In en, this message translates to: + /// **'Filter and sort'** + String get listFilter_tooltip; + + /// No description provided for @listFilter_sortBy. + /// + /// In en, this message translates to: + /// **'Sort by'** + String get listFilter_sortBy; + + /// No description provided for @listFilter_latestMessages. + /// + /// In en, this message translates to: + /// **'Latest messages'** + String get listFilter_latestMessages; + + /// No description provided for @listFilter_heardRecently. + /// + /// In en, this message translates to: + /// **'Heard recently'** + String get listFilter_heardRecently; + + /// No description provided for @listFilter_az. + /// + /// In en, this message translates to: + /// **'A-Z'** + String get listFilter_az; + + /// No description provided for @listFilter_filters. + /// + /// In en, this message translates to: + /// **'Filters'** + String get listFilter_filters; + + /// No description provided for @listFilter_all. + /// + /// In en, this message translates to: + /// **'All'** + String get listFilter_all; + + /// No description provided for @listFilter_users. + /// + /// In en, this message translates to: + /// **'Users'** + String get listFilter_users; + + /// No description provided for @listFilter_repeaters. + /// + /// In en, this message translates to: + /// **'Repeaters'** + String get listFilter_repeaters; + + /// No description provided for @listFilter_roomServers. + /// + /// In en, this message translates to: + /// **'Room servers'** + String get listFilter_roomServers; + + /// No description provided for @listFilter_unreadOnly. + /// + /// In en, this message translates to: + /// **'Unread only'** + String get listFilter_unreadOnly; + + /// No description provided for @listFilter_newGroup. + /// + /// In en, this message translates to: + /// **'New group'** + String get listFilter_newGroup; +} + +class _AppLocalizationsDelegate + extends LocalizationsDelegate { + const _AppLocalizationsDelegate(); + + @override + Future load(Locale locale) { + return SynchronousFuture(lookupAppLocalizations(locale)); + } + + @override + bool isSupported(Locale locale) => [ + 'bg', + 'de', + 'en', + 'es', + 'fr', + 'it', + 'nl', + 'pl', + 'pt', + 'sk', + 'sl', + 'sv', + 'zh', + ].contains(locale.languageCode); + + @override + bool shouldReload(_AppLocalizationsDelegate old) => false; +} + +AppLocalizations lookupAppLocalizations(Locale locale) { + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + case 'bg': + return AppLocalizationsBg(); + case 'de': + return AppLocalizationsDe(); + case 'en': + return AppLocalizationsEn(); + case 'es': + return AppLocalizationsEs(); + case 'fr': + return AppLocalizationsFr(); + case 'it': + return AppLocalizationsIt(); + case 'nl': + return AppLocalizationsNl(); + case 'pl': + return AppLocalizationsPl(); + case 'pt': + return AppLocalizationsPt(); + case 'sk': + return AppLocalizationsSk(); + case 'sl': + return AppLocalizationsSl(); + case 'sv': + return AppLocalizationsSv(); + case 'zh': + return AppLocalizationsZh(); + } + + throw FlutterError( + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.', + ); +} diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart new file mode 100644 index 0000000..5def822 --- /dev/null +++ b/lib/l10n/app_localizations_bg.dart @@ -0,0 +1,2393 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Bulgarian (`bg`). +class AppLocalizationsBg extends AppLocalizations { + AppLocalizationsBg([String locale = 'bg']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Контакти'; + + @override + String get nav_channels => 'Канали'; + + @override + String get nav_map => 'Карта'; + + @override + String get common_cancel => 'Отказ'; + + @override + String get common_connect => 'Свържи се'; + + @override + String get common_unknownDevice => 'Неизвестно устройство'; + + @override + String get common_save => 'Запази'; + + @override + String get common_delete => 'Изтрий'; + + @override + String get common_close => 'Затвори'; + + @override + String get common_edit => 'Редактирай'; + + @override + String get common_add => 'Добави'; + + @override + String get common_settings => 'Настройки'; + + @override + String get common_disconnect => 'Прекъсни'; + + @override + String get common_connected => 'Свързано'; + + @override + String get common_disconnected => 'Откъснато'; + + @override + String get common_create => 'Създай'; + + @override + String get common_continue => 'Продължи'; + + @override + String get common_share => 'Сподели'; + + @override + String get common_copy => 'Копирай'; + + @override + String get common_retry => 'Опитай отново'; + + @override + String get common_hide => 'Скриване'; + + @override + String get common_remove => 'Изтрий'; + + @override + String get common_enable => 'Активирай'; + + @override + String get common_disable => 'Деактивирай'; + + @override + String get common_reboot => 'Рестартирай'; + + @override + String get common_loading => 'Зареждане...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Сканиране за устройства...'; + + @override + String get scanner_connecting => 'Свързвам се...'; + + @override + String get scanner_disconnecting => 'Изключване...'; + + @override + String get scanner_notConnected => 'Не е свързан'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Свързано с $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Търсене на устройства MeshCore...'; + + @override + String get scanner_tapToScan => + 'Натиснете Сканиране, за да намерите устройства MeshCore.'; + + @override + String scanner_connectionFailed(String error) { + return 'Връзката не успя: $error'; + } + + @override + String get scanner_stop => 'Спрете'; + + @override + String get scanner_scan => 'Сканирай'; + + @override + String get device_quickSwitch => 'Бързо превключване'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Настройки'; + + @override + String get settings_deviceInfo => 'Информация за устройството'; + + @override + String get settings_appSettings => 'Настройки на приложението'; + + @override + String get settings_appSettingsSubtitle => + 'Уведомления, съобщения и предпочитания за карта'; + + @override + String get settings_nodeSettings => 'Настройки на възела'; + + @override + String get settings_nodeName => 'Име на възела'; + + @override + String get settings_nodeNameNotSet => 'Не е зададено'; + + @override + String get settings_nodeNameHint => 'Въведете име на възел'; + + @override + String get settings_nodeNameUpdated => 'Името е актуализирано'; + + @override + String get settings_radioSettings => 'Настройки на радиопредавателя'; + + @override + String get settings_radioSettingsSubtitle => + 'Честота, мощност, разпространяващ фактор'; + + @override + String get settings_radioSettingsUpdated => + 'Радио настройките са актуализирани'; + + @override + String get settings_location => 'Местоположение'; + + @override + String get settings_locationSubtitle => 'Координати на GPS'; + + @override + String get settings_locationUpdated => 'Местоположението е актуализирано'; + + @override + String get settings_locationBothRequired => + 'Въведете както географска ширина, така и географска дължина.'; + + @override + String get settings_locationInvalid => 'Невалидна ширина или дължина.'; + + @override + String get settings_latitude => 'Широчина'; + + @override + String get settings_longitude => 'Дължина'; + + @override + String get settings_privacyMode => 'Режим на поверителност'; + + @override + String get settings_privacyModeSubtitle => + 'Скриване на име/местоположение в рекламите'; + + @override + String get settings_privacyModeToggle => + 'Активирайте режим на поверителност, за да скриете името и местоположението си в рекламите.'; + + @override + String get settings_privacyModeEnabled => + 'Режим на поверителност е активиран'; + + @override + String get settings_privacyModeDisabled => + 'Режим на поверителност е деактивиран'; + + @override + String get settings_actions => 'Действия'; + + @override + String get settings_sendAdvertisement => 'Изпрати Реклама'; + + @override + String get settings_sendAdvertisementSubtitle => 'Сега присъствие в ефир'; + + @override + String get settings_advertisementSent => 'Реклама изпратена'; + + @override + String get settings_syncTime => 'Време за синхронизация'; + + @override + String get settings_syncTimeSubtitle => + 'Задайте часовника на устройството да отговаря на времето на телефона.'; + + @override + String get settings_timeSynchronized => 'Синхронизирано във времето'; + + @override + String get settings_refreshContacts => 'Презареди контакти'; + + @override + String get settings_refreshContactsSubtitle => + 'Презареди списъка с контакти от устройството'; + + @override + String get settings_rebootDevice => 'Рестартирайте устройството'; + + @override + String get settings_rebootDeviceSubtitle => + 'Рестартирайте устройството MeshCore'; + + @override + String get settings_rebootDeviceConfirm => + 'Сигурни ли сте, че искате да рестартирате устройството? Ще бъдете откъснати.'; + + @override + String get settings_debug => 'Отстрани'; + + @override + String get settings_bleDebugLog => 'Лог за отстраняване на грешки на BLE'; + + @override + String get settings_bleDebugLogSubtitle => + 'Команди, отговори и сурови данни BLE'; + + @override + String get settings_appDebugLog => + 'Лог на отстраняване на грешки на приложението'; + + @override + String get settings_appDebugLogSubtitle => + 'Съобщения за отстраняване на грешки на приложението'; + + @override + String get settings_about => 'За нас'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => 'Проект MeshCore с отворен код 2024 г.'; + + @override + String get settings_aboutDescription => + 'Отворен софтуер за Flutter клиент за MeshCore LoRa мрежови устройства.'; + + @override + String get settings_infoName => 'Име'; + + @override + String get settings_infoId => 'ИД'; + + @override + String get settings_infoStatus => 'Статус'; + + @override + String get settings_infoBattery => 'Батерия'; + + @override + String get settings_infoPublicKey => 'Общ публичен ключ'; + + @override + String get settings_infoContactsCount => 'Брой контакти'; + + @override + String get settings_infoChannelCount => 'Брой канали'; + + @override + String get settings_presets => 'Предварителни настройки'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Честота (MHz)'; + + @override + String get settings_frequencyHelper => '300.0 - 2500.0'; + + @override + String get settings_frequencyInvalid => 'Невалидна честота (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Ширина на честотния спектър'; + + @override + String get settings_spreadingFactor => 'Фактор на разпространение'; + + @override + String get settings_codingRate => 'Такса за кодиране'; + + @override + String get settings_txPower => 'TX Мощност (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Невалидна мощност на TX (0-22 dBm)'; + + @override + String get settings_longRange => 'Дълъг обхват'; + + @override + String get settings_fastSpeed => 'Бърза скорост'; + + @override + String settings_error(String message) { + return 'Грешка: $message'; + } + + @override + String get appSettings_title => 'Настройки на приложението'; + + @override + String get appSettings_appearance => 'Външен вид'; + + @override + String get appSettings_theme => 'Тема'; + + @override + String get appSettings_themeSystem => 'Система по подразбиране'; + + @override + String get appSettings_themeLight => 'Ярка'; + + @override + String get appSettings_themeDark => 'Тъмно'; + + @override + String get appSettings_language => 'Език'; + + @override + String get appSettings_languageSystem => 'Система по подразбиране'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Уведомления'; + + @override + String get appSettings_enableNotifications => 'Активирай Известия'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Получете известия за съобщения и реклами'; + + @override + String get appSettings_notificationPermissionDenied => + 'Отказвано е разрешение за известия'; + + @override + String get appSettings_notificationsEnabled => 'Уведомителни са активирани'; + + @override + String get appSettings_notificationsDisabled => 'Известия са изключени'; + + @override + String get appSettings_messageNotifications => 'Уведомления'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Покажи известие при получаване на нови съобщения'; + + @override + String get appSettings_channelMessageNotifications => + 'Уведомления за съобщения от канал'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Покажи известие при получаване на съобщения от канали'; + + @override + String get appSettings_advertisementNotifications => 'Уведомления за реклами'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Покажи известие, когато бъдат открити нови възли.'; + + @override + String get appSettings_messaging => 'Съобщения'; + + @override + String get appSettings_clearPathOnMaxRetry => 'Изчисти Път на Макс Опит'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Възстанови контактния път след 5 неуспешни опита за изпращане'; + + @override + String get appSettings_pathsWillBeCleared => + 'Пътищата ще бъдат почистени след 5 неуспешни опита.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Пътищата няма да бъдат автоматично изчистени.'; + + @override + String get appSettings_autoRouteRotation => + 'Автоматично маршрутизиране на завъртания'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Превключете между най-добрите пътища и режим на наводняване'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Автоматично маршрутизиране вкл.'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Автоматично маршрутизирането е деактивирано'; + + @override + String get appSettings_battery => 'Батерия'; + + @override + String get appSettings_batteryChemistry => 'Химия на батерията'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Зададено за устройство ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Свържете се с устройство, за да изберете.'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3.0-4.2V)'; + + @override + String get appSettings_batteryLifepo4 => 'Литиево желязо фосфат (2.6-3.65V)'; + + @override + String get appSettings_batteryLipo => 'Литиев полимер (3.0-4.2V)'; + + @override + String get appSettings_mapDisplay => 'Карта за показване'; + + @override + String get appSettings_showRepeaters => 'Показване на повторители'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Показване на възпроизвеждащи се възли на картата'; + + @override + String get appSettings_showChatNodes => 'Покажи Възли на Чат'; + + @override + String get appSettings_showChatNodesSubtitle => + 'Показване на чат възли на картата'; + + @override + String get appSettings_showOtherNodes => 'Покажи други възли'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Покажи други типове възли на картата'; + + @override + String get appSettings_timeFilter => 'Филтриране по време'; + + @override + String get appSettings_timeFilterShowAll => 'Покажи всички възли'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Покажи възли от последните $hours часа'; + } + + @override + String get appSettings_mapTimeFilter => 'Филтри за време на картата'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Покажи възлите, открити в:'; + + @override + String get appSettings_allTime => 'Всичко време'; + + @override + String get appSettings_lastHour => 'Последната минута'; + + @override + String get appSettings_last6Hours => 'Последни 6 часа'; + + @override + String get appSettings_last24Hours => 'Последно 24 часа'; + + @override + String get appSettings_lastWeek => 'Миналата седмица'; + + @override + String get appSettings_offlineMapCache => 'Кеш на офлайн карти'; + + @override + String get appSettings_noAreaSelected => 'Няма избрана област'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Избрана е област (мащаб $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Отстрани'; + + @override + String get appSettings_appDebugLogging => + 'Логване за отстраняване на грешки на приложението'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Записване на съобщения за отстраняване на грешки от приложението за отстраняване на грешки.'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'Режимът за отстраняване на грешки в приложението е активиран.'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'Логването за отстраняване на грешки в приложението е изключено.'; + + @override + String get contacts_title => 'Контакти'; + + @override + String get contacts_noContacts => 'Няма контакти към момента.'; + + @override + String get contacts_contactsWillAppear => + 'Контактите ще се появят, когато устройствата рекламират.'; + + @override + String get contacts_searchContacts => 'Търсене на контакти...'; + + @override + String get contacts_noUnreadContacts => 'Няма непрочетени контакти'; + + @override + String get contacts_noContactsFound => 'Няма намерени контакти или групи.'; + + @override + String get contacts_deleteContact => 'Изтрий Контакт'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Изтрий $contactName от контактите?'; + } + + @override + String get contacts_manageRepeater => 'Управление на Повтарящ се Елемент'; + + @override + String get contacts_roomLogin => 'Вход в стаята'; + + @override + String get contacts_openChat => 'Отвори чат'; + + @override + String get contacts_editGroup => 'Редактирай Група'; + + @override + String get contacts_deleteGroup => 'Изтрий група'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Премахнете \"$groupName\"?'; + } + + @override + String get contacts_newGroup => 'Нова група'; + + @override + String get contacts_groupName => 'Група'; + + @override + String get contacts_groupNameRequired => 'Името на групата е задължително.'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'Групата \"$name\" вече съществува.'; + } + + @override + String get contacts_filterContacts => 'Филтрирайте контактите...'; + + @override + String get contacts_noContactsMatchFilter => + 'Няма съвпадения с вашия филтър.'; + + @override + String get contacts_noMembers => 'Няма членове'; + + @override + String get contacts_lastSeenNow => 'Последно видяно сега'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Последна активност $minutes минути преди'; + } + + @override + String get contacts_lastSeenHourAgo => 'Последно видяно преди час'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Последно видян $hours часа преди.'; + } + + @override + String get contacts_lastSeenDayAgo => 'Последно видяно преди 1 ден'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Последно видян $days дни преди.'; + } + + @override + String get channels_title => 'Канали'; + + @override + String get channels_noChannelsConfigured => 'Няма конфигурирани канали'; + + @override + String get channels_addPublicChannel => 'Добави публичен канал'; + + @override + String get channels_searchChannels => 'Търсене на канали...'; + + @override + String get channels_noChannelsFound => 'Няма намерени канали'; + + @override + String channels_channelIndex(int index) { + return 'Канал $index'; + } + + @override + String get channels_hashtagChannel => 'Канал с хаштаг'; + + @override + String get channels_public => 'Публично'; + + @override + String get channels_private => 'Личен'; + + @override + String get channels_publicChannel => 'Публичен канал'; + + @override + String get channels_privateChannel => 'Частен канал'; + + @override + String get channels_editChannel => 'Редактирай канал'; + + @override + String get channels_deleteChannel => 'Изтрий канала'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Изтрий \"$name\"? Това не може да бъде отменено.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Каналът \"$name\" е изтрит'; + } + + @override + String get channels_addChannel => 'Добави Канал'; + + @override + String get channels_channelIndexLabel => 'Индекс на канал'; + + @override + String get channels_channelName => 'Име на канала'; + + @override + String get channels_usePublicChannel => 'Използвайте публичен канал'; + + @override + String get channels_standardPublicPsk => 'Стандартен публичен PSK'; + + @override + String get channels_pskHex => 'PSK (Hex)'; + + @override + String get channels_generateRandomPsk => 'Генерирай случайна PSK'; + + @override + String get channels_enterChannelName => 'Моля, въведете име на канал.'; + + @override + String get channels_pskMustBe32Hex => + 'PSK трябва да бъде 32 шестнаредни знака.'; + + @override + String channels_channelAdded(String name) { + return 'Каналът \"$name\" е добавен'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Редактирай Канал $index'; + } + + @override + String get channels_smazCompression => 'Компресия SMAZ'; + + @override + String channels_channelUpdated(String name) { + return 'Каналът \"$name\" е актуализиран'; + } + + @override + String get channels_publicChannelAdded => 'Публичен канал добавен'; + + @override + String get channels_sortBy => 'Сортирай по'; + + @override + String get channels_sortManual => 'Ръчно'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => 'Последни съобщения'; + + @override + String get channels_sortUnread => 'Непрочетено'; + + @override + String get chat_noMessages => 'Няма съобщения.'; + + @override + String get chat_sendMessageToStart => 'Изпрати съобщение, за да започнеш.'; + + @override + String get chat_originalMessageNotFound => 'Съобщението не е намерено'; + + @override + String chat_replyingTo(String name) { + return 'Отговарям на $name'; + } + + @override + String chat_replyTo(String name) { + return 'Отговори на $name'; + } + + @override + String get chat_location => 'Местоположение'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Изпрати съобщение на $contactName'; + } + + @override + String get chat_typeMessage => 'Въведете съобщение...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Съобщението е твърде дълго (макс $maxBytes байта).'; + } + + @override + String get chat_messageCopied => 'Съобщението е копирано'; + + @override + String get chat_messageDeleted => 'Съобщението е изтрито'; + + @override + String get chat_retryingMessage => 'Опитваме се отново.'; + + @override + String chat_retryCount(int current, int max) { + return 'Опитай отново $current/$max'; + } + + @override + String get chat_sendGif => 'Изпрати GIF'; + + @override + String get chat_reply => 'Отговори'; + + @override + String get chat_addReaction => 'Добави Реакция'; + + @override + String get chat_me => 'Аз'; + + @override + String get emojiCategorySmileys => 'Емотикони'; + + @override + String get emojiCategoryGestures => 'Жестове'; + + @override + String get emojiCategoryHearts => 'Сърца'; + + @override + String get emojiCategoryObjects => 'Обекти'; + + @override + String get gifPicker_title => 'Изберете GIF'; + + @override + String get gifPicker_searchHint => 'Търсене на GIF-ове...'; + + @override + String get gifPicker_poweredBy => 'Задвижвано от GIPHY'; + + @override + String get gifPicker_noGifsFound => 'Няма намерени GIF файлове.'; + + @override + String get gifPicker_failedLoad => 'Не можа да се заредят GIF файловете'; + + @override + String get gifPicker_failedSearch => 'Неуспешно търсене на GIF-ове'; + + @override + String get gifPicker_noInternet => 'Няма интернет връзка'; + + @override + String get debugLog_appTitle => + 'Лог на отстраняване на грешки на приложението'; + + @override + String get debugLog_bleTitle => 'Лог за отстраняване на грешки на BLE'; + + @override + String get debugLog_copyLog => 'Копирай лог'; + + @override + String get debugLog_clearLog => 'Изчисти логовете'; + + @override + String get debugLog_copied => 'Копирано лого за отстраняване на грешки'; + + @override + String get debugLog_bleCopied => 'Копиран лог от BLE'; + + @override + String get debugLog_noEntries => 'Все още няма дебъг логове.'; + + @override + String get debugLog_enableInSettings => + 'Активирайте отстраняване на грешки в настройките на приложението'; + + @override + String get debugLog_frames => 'Рамки'; + + @override + String get debugLog_rawLogRx => 'Raw Log-RX'; + + @override + String get debugLog_noBleActivity => 'Няма BLE активност към момента.'; + + @override + String debugFrame_length(int count) { + return 'Дължина на кадъра: $count байта'; + } + + @override + String debugFrame_command(String value) { + return 'Команда: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Съобщение:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Дестинация Публичен Ключ: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Време: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Флагове: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Тип текст: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Просто'; + + @override + String debugFrame_text(String text) { + return '- Текст: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Хексадесетичен Dump:'; + + @override + String get chat_pathManagement => 'Управление на пътища'; + + @override + String get chat_routingMode => 'Режим на маршрутизиране'; + + @override + String get chat_autoUseSavedPath => 'Автоматично (използвай запазения път)'; + + @override + String get chat_forceFloodMode => 'Принуди режим на наводняване'; + + @override + String get chat_recentAckPaths => + 'Неотдавни ACK пътища (докоснете, за да използвате):'; + + @override + String get chat_pathHistoryFull => + 'Историята на пътя е пълна. Премахнете записи, за да добавите нови.'; + + @override + String get chat_hopSingular => 'скочи'; + + @override + String get chat_hopPlural => 'скоци'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'Успехи'; + + @override + String get chat_removePath => 'Премахни пътя'; + + @override + String get chat_noPathHistoryYet => + 'Няма история на пътищата още.\nИзпратете съобщение, за да откриете пътища.'; + + @override + String get chat_pathActions => 'Действия по пътя:'; + + @override + String get chat_setCustomPath => 'Задайте персонализиран път'; + + @override + String get chat_setCustomPathSubtitle => 'Ръчно укажете маршрутен път'; + + @override + String get chat_clearPath => 'Почисти Път'; + + @override + String get chat_clearPathSubtitle => + 'Принуди преоткриване при следващо изпращане'; + + @override + String get chat_pathCleared => + 'Пътят е почистен. Следващото съобщение ще открие маршрута отново.'; + + @override + String get chat_floodModeSubtitle => + 'Използвайте превключвателя за маршрутизиране в лентата на приложението.'; + + @override + String get chat_floodModeEnabled => + 'Режим на наводнение е активиран. Включете го отново чрез иконката за маршрутизиране в лентата на приложението.'; + + @override + String get chat_fullPath => 'Пълен път'; + + @override + String get chat_pathDetailsNotAvailable => + 'Детайлите за пътя все още не са налични. Опитайте да изпратите съобщение, за да освежите.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Пътят е зададен: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Запазено локално. Свържете се за синхронизиране.'; + + @override + String get chat_pathDeviceConfirmed => 'Устройство потвърдено.'; + + @override + String get chat_pathDeviceNotConfirmed => + 'Устройството все още не е потвърдено.'; + + @override + String get chat_type => 'Въведете'; + + @override + String get chat_path => 'Пътекино'; + + @override + String get chat_publicKey => 'Публичен ключ'; + + @override + String get chat_compressOutgoingMessages => + 'Компресиране на изходящи съобщения'; + + @override + String get chat_floodForced => 'Потоп (принуден)'; + + @override + String get chat_directForced => 'Директно (принудително)'; + + @override + String chat_hopsForced(int count) { + return '$count скока (принудително)'; + } + + @override + String get chat_floodAuto => 'Потоп (автоматично)'; + + @override + String get chat_direct => 'Директно'; + + @override + String get chat_poiShared => 'Споделено място от интерес'; + + @override + String chat_unread(int count) { + return 'Непрочетени: $count'; + } + + @override + String get map_title => 'Карта на възлите'; + + @override + String get map_noNodesWithLocation => 'Няма възли с данни за местоположение.'; + + @override + String get map_nodesNeedGps => + 'Възлагат се възлозите да споделят техните GPS координати,\nза да се появят на картата.'; + + @override + String map_nodesCount(int count) { + return 'Нодове: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Ключове: $count'; + } + + @override + String get map_chat => 'Чат'; + + @override + String get map_repeater => 'Повтарящ се'; + + @override + String get map_room => 'Стая'; + + @override + String get map_sensor => 'Датчик'; + + @override + String get map_pinDm => 'Задържане (DM)'; + + @override + String get map_pinPrivate => 'Задържане (Приватно)'; + + @override + String get map_pinPublic => 'Публичен ключ'; + + @override + String get map_lastSeen => 'Последна видяна'; + + @override + String get map_disconnectConfirm => + 'Сигурни ли сте, че искате да се откъснете от това устройство?'; + + @override + String get map_from => 'От'; + + @override + String get map_source => 'Източник'; + + @override + String get map_flags => 'Флаг'; + + @override + String get map_shareMarkerHere => 'Споделете маркер тук'; + + @override + String get map_pinLabel => 'Етикетиране на пин'; + + @override + String get map_label => 'Етикет'; + + @override + String get map_pointOfInterest => 'Точка на интерес'; + + @override + String get map_sendToContact => 'Изпрати на контакт'; + + @override + String get map_sendToChannel => 'Изпрати в канала'; + + @override + String get map_noChannelsAvailable => 'Няма налични канали'; + + @override + String get map_publicLocationShare => 'Споделяне на публично място'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'Ще споделите местоположение в $channelLabel. Този канал е публичен и всеки с PSK може да го види.'; + } + + @override + String get map_connectToShareMarkers => + 'Свържете се с устройство, за да споделите маркери.'; + + @override + String get map_filterNodes => 'Филтрирайте възли'; + + @override + String get map_nodeTypes => 'Типове възли'; + + @override + String get map_chatNodes => 'Възли на чата'; + + @override + String get map_repeaters => 'Повторители'; + + @override + String get map_otherNodes => 'Други възли'; + + @override + String get map_keyPrefix => 'Префикс на ключа'; + + @override + String get map_filterByKeyPrefix => 'Филтрирайте по префикс на ключ'; + + @override + String get map_publicKeyPrefix => 'Префикс на публичен ключ'; + + @override + String get map_markers => 'Маркери'; + + @override + String get map_showSharedMarkers => 'Покажи споделени маркери'; + + @override + String get map_lastSeenTime => 'Последна видяна дата'; + + @override + String get map_sharedPin => 'Споделено копие'; + + @override + String get map_joinRoom => 'Присъедини се към стаята'; + + @override + String get map_manageRepeater => 'Управление на Повтарящ се Елемент'; + + @override + String get mapCache_title => 'Кеш на офлайн карти'; + + @override + String get mapCache_selectAreaFirst => 'Изберете област за кеширане първа'; + + @override + String get mapCache_noTilesToDownload => + 'Няма плочки за изтегляне за тази област.'; + + @override + String get mapCache_downloadTilesTitle => 'Изтегли плочки'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Изтегли $count плочки за офлайн употреба?'; + } + + @override + String get mapCache_downloadAction => 'Изтегли'; + + @override + String mapCache_cachedTiles(int count) { + return 'Кеширани $count плочки'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Запазени $downloaded плочки ($failed неуспешни)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => 'Изчисти офлайн кеша'; + + @override + String get mapCache_clearOfflineCachePrompt => + 'Премахнете всички кеширани плочки на картата?'; + + @override + String get mapCache_offlineCacheCleared => + 'Кешът на устройството е изчистен.'; + + @override + String get mapCache_noAreaSelected => 'Няма избрана област'; + + @override + String get mapCache_cacheArea => 'Област с кеш'; + + @override + String get mapCache_useCurrentView => 'Използвайте текущия изглед'; + + @override + String get mapCache_zoomRange => 'Обхват на увеличението'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Очаквани плочки: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Изтеглено $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Изтегли Плочки'; + + @override + String get mapCache_clearCacheButton => 'Изчисти кеша'; + + @override + String mapCache_failedDownloads(int count) { + return 'Неуспешни изтегляния: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'Север $north, Юг $south, Изток $east, Запад $west'; + } + + @override + String get time_justNow => 'Сега'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes минути преди'; + } + + @override + String time_hoursAgo(int hours) { + return '$hours часа преди'; + } + + @override + String time_daysAgo(int days) { + return '$days дни преди'; + } + + @override + String get time_hour => 'час'; + + @override + String get time_hours => 'часове'; + + @override + String get time_day => 'ден'; + + @override + String get time_days => 'дни'; + + @override + String get time_week => 'седмица'; + + @override + String get time_weeks => 'секти'; + + @override + String get time_month => 'месец'; + + @override + String get time_months => 'месеци'; + + @override + String get time_minutes => 'минути'; + + @override + String get time_allTime => 'Всичко време'; + + @override + String get dialog_disconnect => 'Прекъсни'; + + @override + String get dialog_disconnectConfirm => + 'Сигурни ли сте, че искате да се откъснете от това устройство?'; + + @override + String get login_repeaterLogin => 'Повторител Вход'; + + @override + String get login_roomLogin => 'Вход в стаята'; + + @override + String get login_password => 'Парола'; + + @override + String get login_enterPassword => 'Въведете парола'; + + @override + String get login_savePassword => 'Запази парола'; + + @override + String get login_savePasswordSubtitle => + 'Паролата ще бъде съхранена сигурно на това устройство.'; + + @override + String get login_repeaterDescription => + 'Въведете паролата на репитера, за да получите достъп до настройките и статуса.'; + + @override + String get login_roomDescription => + 'Въведете паролата на стаята, за да получите достъп до настройките и статуса.'; + + @override + String get login_routing => 'Маршрутизиране'; + + @override + String get login_routingMode => 'Режим на маршрутизиране'; + + @override + String get login_autoUseSavedPath => 'Автоматично (използвай запазения път)'; + + @override + String get login_forceFloodMode => 'Принуди режим на наводняване'; + + @override + String get login_managePaths => 'Управление на пътища'; + + @override + String get login_login => 'Вход'; + + @override + String login_attempt(int current, int max) { + return 'Опитвате $current/$max'; + } + + @override + String login_failed(String error) { + return 'Входът не беше успешен: $error'; + } + + @override + String get common_reload => 'Презареди'; + + @override + String get common_clear => 'Изчисти'; + + @override + String path_currentPath(String path) { + return 'Текущ път: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Използване на $count $_temp0 път'; + } + + @override + String get path_enterCustomPath => 'Въведете персонализиран път'; + + @override + String get path_currentPathLabel => 'Текущ път'; + + @override + String get path_hexPrefixInstructions => + 'Въведете 2-символни шестнадесетични префикси за всеки хоп, разделени с кама.'; + + @override + String get path_hexPrefixExample => + 'A1,F2,3C (всяка нода използва първия байт от публичния си ключ)'; + + @override + String get path_labelHexPrefixes => 'Пътеки (шестнадесетични префикси)'; + + @override + String get path_helperMaxHops => + 'Максимум 64 скока. Всеки префикс е 2 шестнадесетични знака (1 байт).'; + + @override + String get path_selectFromContacts => 'Изберете от контакти:'; + + @override + String get path_noRepeatersFound => + 'Няма намерени репетитори или сървъри на стаи.'; + + @override + String get path_customPathsRequire => + 'Персонализираните пътища изискват междинни скокове, които могат да препращат съобщения.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Невалидни шестнадесетични префикси: $prefixes'; + } + + @override + String get path_tooLong => + 'Пътят е твърде дълъг. Максимум 64 скока са разрешени.'; + + @override + String get path_setPath => 'Задайте път'; + + @override + String get repeater_management => 'Управление на повторители'; + + @override + String get repeater_managementTools => 'Инструменти за управление'; + + @override + String get repeater_status => 'Статус'; + + @override + String get repeater_statusSubtitle => + 'Прегледайте статуса, статистиката и съседните устройства.'; + + @override + String get repeater_telemetry => 'Телеметрия'; + + @override + String get repeater_telemetrySubtitle => + 'Прегледайте телеметрията на сензорите и системните статистики'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Изпрати команди към ретранслатора'; + + @override + String get repeater_settings => 'Настройки'; + + @override + String get repeater_settingsSubtitle => + 'Конфигурирайте параметрите на репитера'; + + @override + String get repeater_statusTitle => 'Статус на повтарянето'; + + @override + String get repeater_routingMode => 'Режим на маршрутизиране'; + + @override + String get repeater_autoUseSavedPath => + 'Автоматично (използвай запазения път)'; + + @override + String get repeater_forceFloodMode => 'Принуди режим на наводняване'; + + @override + String get repeater_pathManagement => 'Управление на пътища'; + + @override + String get repeater_refresh => 'Презареди'; + + @override + String get repeater_statusRequestTimeout => + 'Заявката за статус премина прекалено дълго.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Грешка при зареждане на статуса: $error'; + } + + @override + String get repeater_systemInformation => 'Информация за системата'; + + @override + String get repeater_battery => 'Батерия'; + + @override + String get repeater_clockAtLogin => 'Часовник (при влизане)'; + + @override + String get repeater_uptime => 'Наличност'; + + @override + String get repeater_queueLength => 'Дължина на опашката'; + + @override + String get repeater_debugFlags => 'Контролни точки за отстраняване на грешки'; + + @override + String get repeater_radioStatistics => 'Статистика на радиостанциите'; + + @override + String get repeater_lastRssi => 'Последна RSSI'; + + @override + String get repeater_lastSnr => 'Последна SNR'; + + @override + String get repeater_noiseFloor => 'Ниво на шум'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Статистика на пакетите'; + + @override + String get repeater_sent => 'Изпратено'; + + @override + String get repeater_received => 'Получено'; + + @override + String get repeater_duplicates => 'Дубликати'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days дни $hoursч $minutesм $secondsс'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Общо: $total, Наводнение: $flood, Директно: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Общо: $total, Наводнение: $flood, Директно: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Поливане: $flood, Директен: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Общо: $total'; + } + + @override + String get repeater_settingsTitle => 'Настройки на повтарящия се елемент'; + + @override + String get repeater_basicSettings => 'Основни настройки'; + + @override + String get repeater_repeaterName => 'Име на повтарящ се елемент'; + + @override + String get repeater_repeaterNameHelper => + 'Показване на името на този репитер'; + + @override + String get repeater_adminPassword => 'Парола на администратора'; + + @override + String get repeater_adminPasswordHelper => 'Пълен достъпен парола'; + + @override + String get repeater_guestPassword => 'Парола на гост'; + + @override + String get repeater_guestPasswordHelper => 'Достъп с ограничен достъп'; + + @override + String get repeater_radioSettings => 'Настройки на радиостанцията'; + + @override + String get repeater_frequencyMhz => 'Честота (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Power'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Ширина на честотния спектър'; + + @override + String get repeater_spreadingFactor => 'Фактор на разпространение'; + + @override + String get repeater_codingRate => 'Такса за кодиране'; + + @override + String get repeater_locationSettings => 'Настройки на местоположението'; + + @override + String get repeater_latitude => 'Широчина'; + + @override + String get repeater_latitudeHelper => 'Десетични градуси (напр. 37.7749)'; + + @override + String get repeater_longitude => 'Дължина'; + + @override + String get repeater_longitudeHelper => + 'Градуси с десетични знаци (напр. -122.4194)'; + + @override + String get repeater_features => 'Характеристики'; + + @override + String get repeater_packetForwarding => 'Пренасочване на пакети'; + + @override + String get repeater_packetForwardingSubtitle => + 'Активирайте репитера, за да препращате пакети.'; + + @override + String get repeater_guestAccess => 'Достъп за Гост'; + + @override + String get repeater_guestAccessSubtitle => 'Разрешете самочетене за гости'; + + @override + String get repeater_privacyMode => 'Режим на поверителност'; + + @override + String get repeater_privacyModeSubtitle => + 'Скриване на име/местоположение в рекламите'; + + @override + String get repeater_advertisementSettings => 'Настройки на рекламите'; + + @override + String get repeater_localAdvertInterval => 'Местен Рекламен Интервал'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes минути'; + } + + @override + String get repeater_floodAdvertInterval => + 'Интервал на рекламата за наводнения'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours часа'; + } + + @override + String get repeater_encryptedAdvertInterval => 'Криптиран Рекламен Интервал'; + + @override + String get repeater_dangerZone => + 'Опасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно Безопасно'; + + @override + String get repeater_rebootRepeater => 'БеРестартирай Репитер'; + + @override + String get repeater_rebootRepeaterSubtitle => 'Рестартирайте ретранслатора.'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Сигурни ли сте, че искате да рестартирате този репитер?'; + + @override + String get repeater_regenerateIdentityKey => + 'Генериране на Ключ за Идентичност'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Генериране на нова двойка публичен/частен ключ'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'БеТова ще генерира нова идентичност за репитера. Продължете?'; + + @override + String get repeater_eraseFileSystem => 'Изтрий Файлова Система'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Форматирайте файла на репитера'; + + @override + String get repeater_eraseFileSystemConfirm => + 'ВНИМАНИЕ: Това ще изтрие всички данни от репетитора. Това не може да бъде отменено!'; + + @override + String get repeater_eraseSerialOnly => + 'Изтриването е достъпно само през серийния терминал.'; + + @override + String repeater_commandSent(String command) { + return 'Командата е изпратена: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Грешка при изпращане на командата: $error'; + } + + @override + String get repeater_confirm => 'БеПотвърди'; + + @override + String get repeater_settingsSaved => 'Настройките са запазени успешно.'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Грешка при запазване на настройките: $error'; + } + + @override + String get repeater_refreshBasicSettings => 'Обнови Основни Настройки'; + + @override + String get repeater_refreshRadioSettings => + 'Обнови настройките на радиопредавателите'; + + @override + String get repeater_refreshTxPower => 'Обнови TX захранване'; + + @override + String get repeater_refreshLocationSettings => + 'Обнови настройките на местоположението'; + + @override + String get repeater_refreshPacketForwarding => 'Обнови пакетно пренасочване'; + + @override + String get repeater_refreshGuestAccess => 'Обнови достъп за гости'; + + @override + String get repeater_refreshPrivacyMode => 'Обнови Режим на поверителност'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Обнови Настройки на Рекламата'; + + @override + String repeater_refreshed(String label) { + return '$label е обновено'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Грешка при обновяване на $label'; + } + + @override + String get repeater_cliTitle => 'Повторител CLI'; + + @override + String get repeater_debugNextCommand => 'Поправи Следваща Команда'; + + @override + String get repeater_commandHelp => 'Помощ'; + + @override + String get repeater_clearHistory => 'Изчисти История'; + + @override + String get repeater_noCommandsSent => 'Няма изпратени команди засега.'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Въведете команда по-долу или използвайте бързи команди'; + + @override + String get repeater_enterCommandHint => 'Въведете команда...'; + + @override + String get repeater_previousCommand => 'Предходна команда'; + + @override + String get repeater_nextCommand => 'Следваща команда'; + + @override + String get repeater_enterCommandFirst => 'Въведете първо команда.'; + + @override + String get repeater_cliCommandFrameTitle => 'Рамка за команда CLI'; + + @override + String repeater_cliCommandError(String error) { + return 'Грешка: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Получи име'; + + @override + String get repeater_cliQuickGetRadio => 'Получи радио'; + + @override + String get repeater_cliQuickGetTx => 'Получи TX'; + + @override + String get repeater_cliQuickNeighbors => 'Съседи'; + + @override + String get repeater_cliQuickVersion => 'Версия'; + + @override + String get repeater_cliQuickAdvertise => 'Рекламирай'; + + @override + String get repeater_cliQuickClock => 'Часовник'; + + @override + String get repeater_cliHelpAdvert => 'Изпраща рекламен пакет'; + + @override + String get repeater_cliHelpReboot => + 'Рестартира устройството. (Забележка, може да получите \'Timeout\', което е нормално)'; + + @override + String get repeater_cliHelpClock => + 'Показва текущото време според часовника на всяко устройство.'; + + @override + String get repeater_cliHelpPassword => + 'Задава се нова администраторска парола за устройството.'; + + @override + String get repeater_cliHelpVersion => + 'Показва версията на устройството и датата на компилация на фърмуера.'; + + @override + String get repeater_cliHelpClearStats => + 'Рестартира различни статистики броячи до нула.'; + + @override + String get repeater_cliHelpSetAf => 'Задава времето на фактора.'; + + @override + String get repeater_cliHelpSetTx => + 'Задава се мощността на предаване на LoRa в dBm (отчитане спрямо референтно ниво).'; + + @override + String get repeater_cliHelpSetRepeat => + 'Активира или деактивира ролята на репитера за този възел.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Сървър на стаята) Ако е \"включено\", тогава влизането с празен парола ще бъде разрешено, но не може да публикува в стаята (само четене).'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Задава максималния брой хопове на входящ пакет за заливване (ако >= max, пакетът не се предава).'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Задава праг на интерференцията (в dB). По подразбиране е 14. Задайте на 0, за да деактивирате откриването на интерференция на каналите.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Задава интервала за рестартиране на Автоматичния контролер за усилване. Задайте на 0, за да го деактивирате.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Активира или деактивира функцията \'двойни ACKs\'.'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Задава интервала на таймера в минути за изпращане на локален (безпроблемен) рекламен пакет. Задайте на 0, за да го деактивирате.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Задава интервала на таймера в часове за изпращане на пакет с реклама за наводнение. Задайте на 0, за да го деактивирате.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Задава/обновява паролата на гост. (за повторители, гостите могат да изпращат заявката \"Get Stats\")'; + + @override + String get repeater_cliHelpSetName => 'Задава име на обявата.'; + + @override + String get repeater_cliHelpSetLat => + 'Задава географска ширина на картата с реклами (в десетими градуси).'; + + @override + String get repeater_cliHelpSetLon => + 'Задава обхвата на дължина на картата на рекламата. (десетими градуса)'; + + @override + String get repeater_cliHelpSetRadio => + 'Задава напълно нови радио параметри и ги запазва в предпочитанията. Изисква команда \"рестарт\", за да бъдат приложени.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Зададени (експериментални) основи (трябва да е > 1 за ефект) за прилагане на леко забавяне на получените пакети, базирано на силата на сигнала/резултата. Задайте на 0, за да го деактивирате.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Задава фактор, умножен по времето на въздух за пакет в режим на наводнение и с рандомизирана система за слотове, за да забави предаването му (за да намали вероятността от сблъсъци).'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Същото като txdelay, но за прилагане на случайна забавяне при препращането на пакети в директен режим.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => + 'Активиране/Деактивиране на мост.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Задайте забавяне преди преизпращане на пакети.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Изберете дали мостът ще предава препратени пакети или получени пакети.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Задайте скоростта на предаване за RS232 мостовете.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Задайте тайна за мостовете на EspNow.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Задава персонализиран коефициент за коригиране на отчетеното напрежение на батерията (поддържа се само на избрани дъски).'; + + @override + String get repeater_cliHelpTempRadio => + 'Задава временни радио параметри за посочения брой минути, връщайки се към оригиналните радио параметри след това. (не се запазва в предпочитанията).'; + + @override + String get repeater_cliHelpSetPerm => + 'Променя ACL. Премахва съответстващия запис (по префикс на pubkey), ако \"permissions\" е нула. Добавя нов запис, ако pubkey-hex е с пълна дължина и не е в ACL. Актуализира запис, съответстващ на префикса на pubkey. Битовете за разрешения варират според ролята на firmware, но долните 2 бита са: 0 (Гост), 1 (Само четене), 2 (Четене и писане), 3 (Администратор).'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Получава тип мост none, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => + 'Започва записване на пакети във файловата система.'; + + @override + String get repeater_cliHelpLogStop => + 'Спира записването на пакети във файловата система.'; + + @override + String get repeater_cliHelpLogErase => + 'Изтрива логовете от пакета от файловата система.'; + + @override + String get repeater_cliHelpNeighbors => + 'Показва списък с други възли на репитер, чути чрез нулев хоп реклами. Всяка линия е id-prefix-hex:timestamp:snr-times-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Премахва първия съвпадащ запис (по префикси на pubkey (hex)) от списъка с съседи.'; + + @override + String get repeater_cliHelpRegion => + '(сериен режим) Изброява всички дефинирани региони и текущите разрешения за наводнения.'; + + @override + String get repeater_cliHelpRegionLoad => + 'Забележка: това е специално многокомандно извикване. Всяка следваща команда е име на регион (отстъпен с интервали, за да се покаже йерархията, с минимум един интервал). Завършва се чрез изпращане на празен ред/команда.'; + + @override + String get repeater_cliHelpRegionGet => + 'Търси регион с даден префикс на име (или \"\" за глобалния обхват). Отговаря с \"-> region-name (parent-name) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Добавя или актуализира дефиниция на регион с дадено име.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Премахва дефиниция на регион с дадено име. (трябва да съвпада точно и да няма подрегиони)'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Задава \'Потоп\' разрешение за посочената област. (\'\' за глобалния/стария обхват)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Премахва разрешението \"F\"лоуд за посочената област. (ЗАБЕЛЕЖКА: в момента не се препоръчва да се използва на глобалното/старото ниво!! )'; + + @override + String get repeater_cliHelpRegionHome => + 'Отговаря с текущия \'home\' регион. (Забележка: не е приложена никъде, запазена за бъдещи нужди).'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Задава \'домашно\' региона.'; + + @override + String get repeater_cliHelpRegionSave => + 'Запазва списъка/картата с региони в съхранение.'; + + @override + String get repeater_cliHelpGps => + 'Показва статуса на GPS. Когато GPS е изключен, отговаря само с \"off\", ако е включен отговаря с \"on\", статус, fix, брой на сателити.'; + + @override + String get repeater_cliHelpGpsOnOff => 'Включва/Изключва GPS захранването.'; + + @override + String get repeater_cliHelpGpsSync => + 'Синхронизира времето на възела с GPS часовника.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Задава координатите на нодата по GPS и запазва предпочитанията.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Предоставя конфигурацията на рекламата за местоположението на възела:\n- none: не включвайте местоположението в рекламите\n- share: споделяйте gps местоположението (от SensorManager)\n- prefs: рекламирайте местоположението, съхранено в предпочитанията'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Задава конфигурация на обявите за местоположение.'; + + @override + String get repeater_commandsListTitle => 'Списък с команди'; + + @override + String get repeater_commandsListNote => + 'ЗАБЕЛЕЖКА: за различните команди \"set ...\", също така съществува команда \"get ...\".'; + + @override + String get repeater_general => 'Общо'; + + @override + String get repeater_settingsCategory => 'Настройки'; + + @override + String get repeater_bridge => 'Мост'; + + @override + String get repeater_logging => 'Логване'; + + @override + String get repeater_neighborsRepeaterOnly => 'Съседи (Само за повтаряне)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Управление на региони (Само за повтарящ се канал)'; + + @override + String get repeater_regionNote => + 'Регионните команди са въведени, за да управляват дефинициите и разрешенията на регионите.'; + + @override + String get repeater_gpsManagement => 'Управление на GPS'; + + @override + String get repeater_gpsNote => + 'GPS командата е въведена, за да управлява теми, свързани с местоположението.'; + + @override + String get telemetry_receivedData => 'Получени телеметрични данни'; + + @override + String get telemetry_requestTimeout => 'Заявката за телеметрия е прекъсната.'; + + @override + String telemetry_errorLoading(String error) { + return 'Грешка при зареждане на телеметрията: $error'; + } + + @override + String get telemetry_noData => 'Няма налични данни за телеметрията.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Канал $channel'; + } + + @override + String get telemetry_batteryLabel => 'Батерия'; + + @override + String get telemetry_voltageLabel => 'Напрежение'; + + @override + String get telemetry_mcuTemperatureLabel => 'Температура на MCU'; + + @override + String get telemetry_temperatureLabel => 'Температура'; + + @override + String get telemetry_currentLabel => 'Текущо'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Пътеки пъзел'; + + @override + String get channelPath_viewMap => 'Преглед на картата'; + + @override + String get channelPath_otherObservedPaths => 'Други Наблюдавани Пътища'; + + @override + String get channelPath_repeaterHops => 'Повтарящи се скокове'; + + @override + String get channelPath_noHopDetails => + 'Детайлите за пакета не са предоставени.'; + + @override + String get channelPath_messageDetails => 'Подробности на съобщението'; + + @override + String get channelPath_senderLabel => 'Изпращач'; + + @override + String get channelPath_timeLabel => 'Време'; + + @override + String get channelPath_repeatsLabel => 'Повтаря'; + + @override + String channelPath_pathLabel(int index) { + return 'Път $index'; + } + + @override + String get channelPath_observedLabel => 'Наблюдавано'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Наблюдаван път $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'Няма данни за местоположение.'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Неизвестно'; + + @override + String get channelPath_floodPath => 'Поливане'; + + @override + String get channelPath_directPath => 'Директно'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 от $total скокове'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed от $total скокове'; + } + + @override + String get channelPath_mapTitle => 'Карта на пътя'; + + @override + String get channelPath_noRepeaterLocations => + 'Няма налични местоположения на повторителите за този път.'; + + @override + String channelPath_primaryPath(int index) { + return 'Път $index (Основен)'; + } + + @override + String get channelPath_pathLabelTitle => 'Пътекино'; + + @override + String get channelPath_observedPathHeader => 'Наблюдаван път'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'Няма налични детайли за този пакет.'; + + @override + String get channelPath_unknownRepeater => 'Неизвестен повторител'; + + @override + String get listFilter_tooltip => 'Филтрирайте и сортирайте'; + + @override + String get listFilter_sortBy => 'Сортирай по'; + + @override + String get listFilter_latestMessages => 'Последни съобщения'; + + @override + String get listFilter_heardRecently => 'Слушано е наскоро'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Филтри'; + + @override + String get listFilter_all => 'Всички'; + + @override + String get listFilter_users => 'Потребители'; + + @override + String get listFilter_repeaters => 'Повторители'; + + @override + String get listFilter_roomServers => 'Сървъри на стая'; + + @override + String get listFilter_unreadOnly => 'Само непрочетените'; + + @override + String get listFilter_newGroup => 'Нова група'; +} diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart new file mode 100644 index 0000000..591de39 --- /dev/null +++ b/lib/l10n/app_localizations_de.dart @@ -0,0 +1,2395 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for German (`de`). +class AppLocalizationsDe extends AppLocalizations { + AppLocalizationsDe([String locale = 'de']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Kontakte'; + + @override + String get nav_channels => 'Kanäle'; + + @override + String get nav_map => 'Karte'; + + @override + String get common_cancel => 'Abbrechen'; + + @override + String get common_connect => 'Verbinden'; + + @override + String get common_unknownDevice => 'Unbekanntes Gerät'; + + @override + String get common_save => 'Speichern'; + + @override + String get common_delete => 'Löschen'; + + @override + String get common_close => 'Schließen'; + + @override + String get common_edit => 'Bearbeiten'; + + @override + String get common_add => 'Hinzufügen'; + + @override + String get common_settings => 'Einstellungen'; + + @override + String get common_disconnect => 'Trennen'; + + @override + String get common_connected => 'Verbunden'; + + @override + String get common_disconnected => 'Getrennt'; + + @override + String get common_create => 'Erstellen'; + + @override + String get common_continue => 'Fortfahren'; + + @override + String get common_share => 'Teilen'; + + @override + String get common_copy => 'Kopieren'; + + @override + String get common_retry => 'Versuchen'; + + @override + String get common_hide => 'Ausblenden'; + + @override + String get common_remove => 'Löschen'; + + @override + String get common_enable => 'Aktivieren'; + + @override + String get common_disable => 'Deaktivieren'; + + @override + String get common_reboot => 'Neustart'; + + @override + String get common_loading => 'Laden...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Scannen nach Geräten...'; + + @override + String get scanner_connecting => 'Verbunden...'; + + @override + String get scanner_disconnecting => 'Trenne...'; + + @override + String get scanner_notConnected => 'Nicht verbunden'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Verbunden mit $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Suche nach MeshCore-Geräten...'; + + @override + String get scanner_tapToScan => + 'Tippen Sie auf Scan, um MeshCore-Geräte zu finden.'; + + @override + String scanner_connectionFailed(String error) { + return 'Verbindungsfehler: $error'; + } + + @override + String get scanner_stop => 'Stopp'; + + @override + String get scanner_scan => 'Scannen'; + + @override + String get device_quickSwitch => 'Schneller Umschalten'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Einstellungen'; + + @override + String get settings_deviceInfo => 'Geräteinformationen'; + + @override + String get settings_appSettings => 'App-Einstellungen'; + + @override + String get settings_appSettingsSubtitle => + 'Benachrichtigungen, Messaging und Kartenwahrnehmungen'; + + @override + String get settings_nodeSettings => 'Knoten-Einstellungen'; + + @override + String get settings_nodeName => 'Knotenname'; + + @override + String get settings_nodeNameNotSet => 'Nicht festgelegt'; + + @override + String get settings_nodeNameHint => 'Gib den Knotenamen ein'; + + @override + String get settings_nodeNameUpdated => 'Name aktualisiert'; + + @override + String get settings_radioSettings => 'Funk Einstellungen'; + + @override + String get settings_radioSettingsSubtitle => + 'Frequenz, Leistung, Verbreitungsfaktor'; + + @override + String get settings_radioSettingsUpdated => 'Funkparameter aktualisiert'; + + @override + String get settings_location => 'Ort'; + + @override + String get settings_locationSubtitle => 'GPS-Koordinaten'; + + @override + String get settings_locationUpdated => 'Ort aktualisiert'; + + @override + String get settings_locationBothRequired => + 'Bitte geben Sie sowohl Breite als auch Längengrad ein.'; + + @override + String get settings_locationInvalid => 'Ungültige Breiten- oder Längengrade.'; + + @override + String get settings_latitude => 'Breitengrad'; + + @override + String get settings_longitude => 'Längengrad'; + + @override + String get settings_privacyMode => 'Privatschutzzustand'; + + @override + String get settings_privacyModeSubtitle => + 'Verstecken Sie Name/Ort in Anzeigen'; + + @override + String get settings_privacyModeToggle => + 'Aktivieren Sie den Datenschutzzustand, um Ihren Namen und Ihre Standortdaten in Anzeigen zu verbergen.'; + + @override + String get settings_privacyModeEnabled => 'Privatschutzzustand aktiviert'; + + @override + String get settings_privacyModeDisabled => 'Datenschutzmodus deaktiviert'; + + @override + String get settings_actions => 'Aktionen'; + + @override + String get settings_sendAdvertisement => 'Senden Sie Anzeige'; + + @override + String get settings_sendAdvertisementSubtitle => 'Sendungsstatus jetzt'; + + @override + String get settings_advertisementSent => 'Anzeige gesendet'; + + @override + String get settings_syncTime => 'Synchronisierungszeit'; + + @override + String get settings_syncTimeSubtitle => + 'Stelle die Gerätewielfalt auf die Uhrzeit des Telefons ein'; + + @override + String get settings_timeSynchronized => 'Zeit synchronisiert'; + + @override + String get settings_refreshContacts => 'Kontakte aktualisieren'; + + @override + String get settings_refreshContactsSubtitle => + 'Kontakte-Liste vom Gerät neu laden'; + + @override + String get settings_rebootDevice => 'Gerät neu starten'; + + @override + String get settings_rebootDeviceSubtitle => 'MeshCore-Gerät neu starten'; + + @override + String get settings_rebootDeviceConfirm => + 'Sind Sie sicher, dass Sie das Gerät neu starten möchten? Sie werden getrennt.'; + + @override + String get settings_debug => 'Fehlerbehebung'; + + @override + String get settings_bleDebugLog => 'BLE-Debug-Protokoll'; + + @override + String get settings_bleDebugLogSubtitle => + 'BLE-Befehle, Antworten und Rohdaten'; + + @override + String get settings_appDebugLog => 'App-Debug-Protokoll'; + + @override + String get settings_appDebugLogSubtitle => 'Anwendung Debug-Nachrichten'; + + @override + String get settings_about => 'Über'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => 'MeshCore Open Source Projekt 2026'; + + @override + String get settings_aboutDescription => + 'Ein Open-Source-Flutter-Client für MeshCore LoRa-Meshnetzwerkgeräte.'; + + @override + String get settings_infoName => 'Name'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'Status'; + + @override + String get settings_infoBattery => 'Akku'; + + @override + String get settings_infoPublicKey => 'Öffentlicher Schlüssel'; + + @override + String get settings_infoContactsCount => 'Kontakte Anzahl'; + + @override + String get settings_infoChannelCount => 'Kanalanzahl'; + + @override + String get settings_presets => 'Voreinstellungen'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Frequenz (MHz)'; + + @override + String get settings_frequencyHelper => '300,00 - 2.500,00'; + + @override + String get settings_frequencyInvalid => 'Ungültige Frequenz (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Bandbreite'; + + @override + String get settings_spreadingFactor => 'Verteilungsfaktor'; + + @override + String get settings_codingRate => 'Programmierpauschale'; + + @override + String get settings_txPower => 'TX-Leistung (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Ungültige TX-Leistung (0-22 dBm)'; + + @override + String get settings_longRange => 'Langreich'; + + @override + String get settings_fastSpeed => 'Schnelle Geschwindigkeit'; + + @override + String settings_error(String message) { + return 'Fehler: $message'; + } + + @override + String get appSettings_title => 'App-Einstellungen'; + + @override + String get appSettings_appearance => 'Aussehen'; + + @override + String get appSettings_theme => 'Theme'; + + @override + String get appSettings_themeSystem => 'Systemstandard'; + + @override + String get appSettings_themeLight => 'Helligkeit'; + + @override + String get appSettings_themeDark => 'Dunkel'; + + @override + String get appSettings_language => 'Sprache'; + + @override + String get appSettings_languageSystem => 'Systemstandard'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Benachrichtigungen'; + + @override + String get appSettings_enableNotifications => 'Benachrichtigungen aktivieren'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Erhalte Benachrichtigungen für Nachrichten und Anzeigen'; + + @override + String get appSettings_notificationPermissionDenied => + 'Erlaubnis zur Benachrichtigung verweigert'; + + @override + String get appSettings_notificationsEnabled => 'Benachrichtigungen aktiviert'; + + @override + String get appSettings_notificationsDisabled => + 'Benachrichtigungen deaktiviert'; + + @override + String get appSettings_messageNotifications => + 'Nachrichtenbenachrichtigungen'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Zeige Benachrichtigung beim Empfang neuer Nachrichten'; + + @override + String get appSettings_channelMessageNotifications => + 'Kanal-Nachrichten-Benachrichtigungen'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Zeige Benachrichtigung beim Empfangen von Kanalnachrichten'; + + @override + String get appSettings_advertisementNotifications => + 'Werbeanzeigenbenachrichtigungen'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Zeige Benachrichtigung, wenn neue Knoten entdeckt werden.'; + + @override + String get appSettings_messaging => 'Nachrichten'; + + @override + String get appSettings_clearPathOnMaxRetry => + 'Klares Pfad bei Max Wiederholungsversuch'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Zurücksetzen des Kontaktpfads nach 5 fehlgeschlagenen Sendeverboten'; + + @override + String get appSettings_pathsWillBeCleared => + 'Die Pfade werden nach 5 fehlgeschlagenen Versuchen gelöscht.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Die Pfade werden nicht automatisch gelöscht.'; + + @override + String get appSettings_autoRouteRotation => 'Automatische Routenrotation'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Wechseln zwischen den besten Pfaden und dem Fluten'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Automatische Routenrotation aktiviert'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Automatische Routenrotation deaktiviert'; + + @override + String get appSettings_battery => 'Akku'; + + @override + String get appSettings_batteryChemistry => 'Batteriechemie'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Konfiguriert pro Gerät ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Verbinde ein Gerät, um zu wählen'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3,0–4,2 V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6–3,65 V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0–4,2V)'; + + @override + String get appSettings_mapDisplay => 'Kartendarstellung'; + + @override + String get appSettings_showRepeaters => 'Zeige Repeater'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Zeige Repeater-Knoten auf der Karte an'; + + @override + String get appSettings_showChatNodes => 'Zeige Chat-Knoten'; + + @override + String get appSettings_showChatNodesSubtitle => + 'Chat-Knoten auf der Karte anzeigen'; + + @override + String get appSettings_showOtherNodes => 'Zeige andere Knoten'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Andere Knotentypen auf der Karte anzeigen'; + + @override + String get appSettings_timeFilter => 'Zeitfilter'; + + @override + String get appSettings_timeFilterShowAll => 'Alle Knoten anzeigen'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Zeige Knoten der letzten $hours Stunden an'; + } + + @override + String get appSettings_mapTimeFilter => 'Kartent Zeitfilter'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Zeige Knoten, die innerhalb von:'; + + @override + String get appSettings_allTime => 'Alle Zeit'; + + @override + String get appSettings_lastHour => 'Letzter Stunde'; + + @override + String get appSettings_last6Hours => 'Letzte 6 Stunden'; + + @override + String get appSettings_last24Hours => 'Letzte 24 Stunden'; + + @override + String get appSettings_lastWeek => 'Letzte Woche'; + + @override + String get appSettings_offlineMapCache => 'Offline-Karten-Cache'; + + @override + String get appSettings_noAreaSelected => 'Kein Bereich ausgewählt'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Ausgewählte Fläche (Zoom $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Fehlerbehebung'; + + @override + String get appSettings_appDebugLogging => 'App-Debug-Protokollierung'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Protokolliere App-Debug-Nachrichten zur Fehlerbehebung'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'App-Debug-Protokollierung aktiviert'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'App-Debug-Protokollierung deaktiviert'; + + @override + String get contacts_title => 'Kontakte'; + + @override + String get contacts_noContacts => 'No Contacts noch'; + + @override + String get contacts_contactsWillAppear => + 'Kontakte werden angezeigt, wenn Geräte Werbung machen.'; + + @override + String get contacts_searchContacts => 'Suche Kontakte...'; + + @override + String get contacts_noUnreadContacts => 'Keine ungeklärten Kontakte'; + + @override + String get contacts_noContactsFound => + 'Keine Kontakte oder Gruppen gefunden.'; + + @override + String get contacts_deleteContact => 'Löschen Sie Kontakt'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Entfernen $contactName aus den Kontakten?'; + } + + @override + String get contacts_manageRepeater => 'Wiederholung verwalten'; + + @override + String get contacts_roomLogin => 'Raum-Login'; + + @override + String get contacts_openChat => 'Öffnen Sie Chat'; + + @override + String get contacts_editGroup => 'Gruppen bearbeiten'; + + @override + String get contacts_deleteGroup => 'Löschen Gruppe'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Löschen Sie \"$groupName\"?'; + } + + @override + String get contacts_newGroup => 'Neue Gruppe'; + + @override + String get contacts_groupName => 'Gruppenname'; + + @override + String get contacts_groupNameRequired => 'Der Gruppennamen ist erforderlich.'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'Die Gruppe \"$name\" existiert bereits.'; + } + + @override + String get contacts_filterContacts => 'Filtert Kontakte...'; + + @override + String get contacts_noContactsMatchFilter => + 'Keine Kontakte passen zu Ihrem Filter'; + + @override + String get contacts_noMembers => 'Keine Mitglieder'; + + @override + String get contacts_lastSeenNow => 'Letztes Ansehen jetzt'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Letzte Sichtung $minutes Minuten her.'; + } + + @override + String get contacts_lastSeenHourAgo => 'Letzte Sichtung vor 1 Stunde.'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Letzte Aktivität vor $hours Stunden.'; + } + + @override + String get contacts_lastSeenDayAgo => 'Letzte Sichtung vor 1 Tag'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Letzte Sichtung $days Tage zuvor'; + } + + @override + String get channels_title => 'Kanäle'; + + @override + String get channels_noChannelsConfigured => 'Keine Kanäle konfiguriert'; + + @override + String get channels_addPublicChannel => 'Öffentlichen Kanal hinzufügen'; + + @override + String get channels_searchChannels => 'Suche Kanäle...'; + + @override + String get channels_noChannelsFound => 'Keine Kanäle gefunden'; + + @override + String channels_channelIndex(int index) { + return 'Kanal $index'; + } + + @override + String get channels_hashtagChannel => 'Hashtag-Kanal'; + + @override + String get channels_public => 'Öffentlich'; + + @override + String get channels_private => 'Privat'; + + @override + String get channels_publicChannel => 'Öffentlicher Kanal'; + + @override + String get channels_privateChannel => 'Privater Kanal'; + + @override + String get channels_editChannel => 'Kanal bearbeiten'; + + @override + String get channels_deleteChannel => 'Löschen Sie Kanal'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Löschen \"$name\"? Dies kann nicht rückgängig gemacht werden.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Kanal \"$name\" gelöscht'; + } + + @override + String get channels_addChannel => 'Kanal hinzufügen'; + + @override + String get channels_channelIndexLabel => 'Kanalindex'; + + @override + String get channels_channelName => 'Kanalname'; + + @override + String get channels_usePublicChannel => 'Verwende öffentlichen Kanal'; + + @override + String get channels_standardPublicPsk => 'Standard-Öffentliche PSK'; + + @override + String get channels_pskHex => 'PSK (Hex)'; + + @override + String get channels_generateRandomPsk => 'Zufällige PSK generieren'; + + @override + String get channels_enterChannelName => + 'Bitte geben Sie einen Kanalnamen ein.'; + + @override + String get channels_pskMustBe32Hex => + 'Die PSK muss 32 hexadezimale Zeichen haben.'; + + @override + String channels_channelAdded(String name) { + return 'Kanal \"$name\" hinzugefügt'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Bearbeiteten Kanal $index'; + } + + @override + String get channels_smazCompression => 'SMAZ-Komprimierung'; + + @override + String channels_channelUpdated(String name) { + return 'Kanal \"$name\" aktualisiert'; + } + + @override + String get channels_publicChannelAdded => 'Öffentlicher Kanal hinzugefügt'; + + @override + String get channels_sortBy => 'Sortiere nach'; + + @override + String get channels_sortManual => 'Manuelle'; + + @override + String get channels_sortAZ => 'A bis Z'; + + @override + String get channels_sortLatestMessages => 'Letzte Nachrichten'; + + @override + String get channels_sortUnread => 'Unlescht'; + + @override + String get chat_noMessages => 'Noch keine Nachrichten.'; + + @override + String get chat_sendMessageToStart => 'Eine Nachricht senden, um anzufangen.'; + + @override + String get chat_originalMessageNotFound => 'Originalmeldung nicht gefunden'; + + @override + String chat_replyingTo(String name) { + return 'Antworten an $name'; + } + + @override + String chat_replyTo(String name) { + return 'Antworten Sie $name'; + } + + @override + String get chat_location => 'Ort'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Sende eine Nachricht an $contactName'; + } + + @override + String get chat_typeMessage => 'Eine Nachricht eingeben...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Nachricht ist zu lang (max $maxBytes Bytes).'; + } + + @override + String get chat_messageCopied => 'Nachricht kopiert'; + + @override + String get chat_messageDeleted => 'Nachricht gelöscht'; + + @override + String get chat_retryingMessage => 'Versuche es erneut.'; + + @override + String chat_retryCount(int current, int max) { + return 'Versuchen $current/$max'; + } + + @override + String get chat_sendGif => 'GIF senden'; + + @override + String get chat_reply => 'Beantworten'; + + @override + String get chat_addReaction => 'Reaktion hinzufügen'; + + @override + String get chat_me => 'Ich'; + + @override + String get emojiCategorySmileys => 'Emoticons'; + + @override + String get emojiCategoryGestures => 'Gesten'; + + @override + String get emojiCategoryHearts => 'Herz'; + + @override + String get emojiCategoryObjects => 'Objekte'; + + @override + String get gifPicker_title => 'Wähle ein GIF'; + + @override + String get gifPicker_searchHint => 'Suche nach GIFs...'; + + @override + String get gifPicker_poweredBy => 'Angetrieben von GIPHY'; + + @override + String get gifPicker_noGifsFound => 'Keine GIFs gefunden'; + + @override + String get gifPicker_failedLoad => + 'GIF-Dateien konnten nicht geladen werden.'; + + @override + String get gifPicker_failedSearch => 'Suche nach GIFs fehlgeschlagen'; + + @override + String get gifPicker_noInternet => 'Keine Internetverbindung'; + + @override + String get debugLog_appTitle => 'App-Debug-Protokoll'; + + @override + String get debugLog_bleTitle => 'BLE-Debug-Protokoll'; + + @override + String get debugLog_copyLog => 'Kopieren Sie Protokoll'; + + @override + String get debugLog_clearLog => 'Log löschen'; + + @override + String get debugLog_copied => 'Debug-Protokoll kopiert'; + + @override + String get debugLog_bleCopied => 'BLE-Protokoll kopiert'; + + @override + String get debugLog_noEntries => 'No Debug-Protokolle noch verfügbar'; + + @override + String get debugLog_enableInSettings => + 'Aktivieren Sie das App-Debug-Logging in den Einstellungen'; + + @override + String get debugLog_frames => 'Rahmen'; + + @override + String get debugLog_rawLogRx => 'Roh-Log-RX'; + + @override + String get debugLog_noBleActivity => 'No BLE-Aktivität bisher'; + + @override + String debugFrame_length(int count) { + return 'Rahmenlänge: $count Bytes'; + } + + @override + String debugFrame_command(String value) { + return 'Befehl: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Textnachricht-Frame:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Ziel-Pub-Schlüssel: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Zeitstempel: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Flags: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Textart: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Einfach'; + + @override + String debugFrame_text(String text) { + return '- Text: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Hex-Dump:'; + + @override + String get chat_pathManagement => 'Pfadverwaltung'; + + @override + String get chat_routingMode => 'Routenmodus'; + + @override + String get chat_autoUseSavedPath => + 'Automatisch (gespeicherten Pfad verwenden)'; + + @override + String get chat_forceFloodMode => 'Zwangsgelände-Modus erzwingen'; + + @override + String get chat_recentAckPaths => + 'Aktuelle ACK-Pfade (tasten, um zu verwenden):'; + + @override + String get chat_pathHistoryFull => + 'Die Pfadhistorie ist voll. Entferne Einträge, um neue hinzuzufügen.'; + + @override + String get chat_hopSingular => 'Springe'; + + @override + String get chat_hopPlural => 'Hops'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'Hops', + one: 'Hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'Erfolgreiche'; + + @override + String get chat_removePath => 'Pfad entfernen'; + + @override + String get chat_noPathHistoryYet => + 'Noe eine Pfadhistorie vorhanden.\nSende eine Nachricht, um Pfade zu entdecken.'; + + @override + String get chat_pathActions => 'Pfadaktionen:'; + + @override + String get chat_setCustomPath => 'Lege benutzerdefinierten Pfad fest'; + + @override + String get chat_setCustomPathSubtitle => 'Manuelle Routenpfad festlegen'; + + @override + String get chat_clearPath => 'Klares Pfad'; + + @override + String get chat_clearPathSubtitle => + 'Zwinge bei nächster Sendung eine erneute Entdeckung durch.'; + + @override + String get chat_pathCleared => + 'Pfad freigelegt. Nächste Nachricht wird Route neu entdecken.'; + + @override + String get chat_floodModeSubtitle => + 'Verwende den Routingschalter in der App-Leiste'; + + @override + String get chat_floodModeEnabled => + 'Flutmodus aktiviert. Über den Routing-Icon in der App-Leiste wieder aktivieren.'; + + @override + String get chat_fullPath => 'Vollständiger Pfad'; + + @override + String get chat_pathDetailsNotAvailable => + 'Die Pfaddetails sind noch nicht verfügbar. Versuchen Sie, eine Nachricht zu senden, um zu aktualisieren.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Pfad gesetzt: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Gespeichert lokal. Mit Verbinden zum Synchronisieren.'; + + @override + String get chat_pathDeviceConfirmed => 'Gerät bestätigt.'; + + @override + String get chat_pathDeviceNotConfirmed => 'Gerät noch nicht bestätigt.'; + + @override + String get chat_type => 'Gib ein'; + + @override + String get chat_path => 'Pfad'; + + @override + String get chat_publicKey => 'Öffentlicher Schlüssel'; + + @override + String get chat_compressOutgoingMessages => + 'Komprimieren ausgehende Nachrichten'; + + @override + String get chat_floodForced => 'Überschwemmung (erzwungen)'; + + @override + String get chat_directForced => 'Direkt (gezwungen)'; + + @override + String chat_hopsForced(int count) { + return '$count Sprünge (erzwungen)'; + } + + @override + String get chat_floodAuto => 'Überschwemmung (automatisch)'; + + @override + String get chat_direct => 'Direkt'; + + @override + String get chat_poiShared => 'Gemeinsamer POI'; + + @override + String chat_unread(int count) { + return 'Unlescht: $count'; + } + + @override + String get map_title => 'Knotenkarte'; + + @override + String get map_noNodesWithLocation => 'Keine Knoten mit Standortdaten'; + + @override + String get map_nodesNeedGps => + 'Knoten müssen ihre GPS-Koordinaten\nteilen,\num auf der Karte\nerscheinen.'; + + @override + String map_nodesCount(int count) { + return 'Knoten: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Pins: $count'; + } + + @override + String get map_chat => 'Chat'; + + @override + String get map_repeater => 'Wiederholung'; + + @override + String get map_room => 'Raum'; + + @override + String get map_sensor => 'Sensor'; + + @override + String get map_pinDm => 'Sperren (DM)'; + + @override + String get map_pinPrivate => 'Privat-Pin'; + + @override + String get map_pinPublic => 'Öffentliche Taste (PIN)'; + + @override + String get map_lastSeen => 'Letzte Sichtung'; + + @override + String get map_disconnectConfirm => + 'Sind Sie sicher, dass Sie sich von diesem Gerät trennen möchten?'; + + @override + String get map_from => 'Von'; + + @override + String get map_source => 'Quelle'; + + @override + String get map_flags => 'Flaggen'; + + @override + String get map_shareMarkerHere => 'Teilen Sie hier das Marker.'; + + @override + String get map_pinLabel => 'Kennzeichnungslabel'; + + @override + String get map_label => 'Label'; + + @override + String get map_pointOfInterest => 'Punkt von Interesse'; + + @override + String get map_sendToContact => 'Senden an Kontakt'; + + @override + String get map_sendToChannel => 'Senden Sie Kanal'; + + @override + String get map_noChannelsAvailable => 'Keine Kanäle verfügbar'; + + @override + String get map_publicLocationShare => 'Öffentliche Standortfreigabe'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'Sie werden kurz darauf einen Ort in $channelLabel teilen. Dieser Kanal ist öffentlich und jeder mit dem PSK kann ihn sehen.'; + } + + @override + String get map_connectToShareMarkers => + 'Verbinde ein Gerät, um Marker zu teilen'; + + @override + String get map_filterNodes => 'Filter Knoten'; + + @override + String get map_nodeTypes => 'Knotentypen'; + + @override + String get map_chatNodes => 'Chat-Knoten'; + + @override + String get map_repeaters => 'Wiederholer'; + + @override + String get map_otherNodes => 'Andere Knoten'; + + @override + String get map_keyPrefix => 'Schlüsselpräfix'; + + @override + String get map_filterByKeyPrefix => 'Filter nach Schlüsselpräfix'; + + @override + String get map_publicKeyPrefix => 'Öffentlicher Schlüsselpräfix'; + + @override + String get map_markers => 'Marker'; + + @override + String get map_showSharedMarkers => 'Zeige gemeinsam genutzte Marker'; + + @override + String get map_lastSeenTime => 'Letzte Sichtung'; + + @override + String get map_sharedPin => 'Gemeinsames Passwort'; + + @override + String get map_joinRoom => 'Beitreten Sie dem Raum'; + + @override + String get map_manageRepeater => 'Wiederholung verwalten'; + + @override + String get mapCache_title => 'Offline-Karten-Cache'; + + @override + String get mapCache_selectAreaFirst => + 'Wählen Sie zuerst einen Bereich zum Zwischenspeichern aus.'; + + @override + String get mapCache_noTilesToDownload => + 'Keine Tiles für diese Region zum Herunterladen verfügbar.'; + + @override + String get mapCache_downloadTilesTitle => 'Herunterladen von Tiles'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Laden $count Tiles für den Offline-Bereich herunter?'; + } + + @override + String get mapCache_downloadAction => 'Herunterladen'; + + @override + String mapCache_cachedTiles(int count) { + return 'Zwischengespeicherte $count Fliesen'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Zwischengespeicherte $downloaded Tiles ($failed fehlgeschlagen)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => 'Leeren Offline-Cache'; + + @override + String get mapCache_clearOfflineCachePrompt => + 'Alle zwischengespeicherten Kartenraster entfernen?'; + + @override + String get mapCache_offlineCacheCleared => 'Offline-Cache gelöscht'; + + @override + String get mapCache_noAreaSelected => 'Kein Bereich ausgewählt'; + + @override + String get mapCache_cacheArea => 'Zwischenspeicherbereich'; + + @override + String get mapCache_useCurrentView => 'Aktuelle Ansicht verwenden'; + + @override + String get mapCache_zoomRange => 'Zoom Bereich'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Geschätzte Fliesen: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Heruntergeladen $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Herunterladen von Tiles'; + + @override + String get mapCache_clearCacheButton => 'Cache leeren'; + + @override + String mapCache_failedDownloads(int count) { + return 'Fehlgeschlagene Downloads: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Gerade eben'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes Minuten her'; + } + + @override + String time_hoursAgo(int hours) { + return '$hours Stunden her'; + } + + @override + String time_daysAgo(int days) { + return '$days Tage/Tage zuvor'; + } + + @override + String get time_hour => 'Stunde'; + + @override + String get time_hours => 'Stunden'; + + @override + String get time_day => 'Tag'; + + @override + String get time_days => 'Tage'; + + @override + String get time_week => 'Woche'; + + @override + String get time_weeks => 'Wochen'; + + @override + String get time_month => 'Monat'; + + @override + String get time_months => 'Monate'; + + @override + String get time_minutes => 'Minuten'; + + @override + String get time_allTime => 'Alle Zeit'; + + @override + String get dialog_disconnect => 'Trennen'; + + @override + String get dialog_disconnectConfirm => + 'Sind Sie sicher, dass Sie sich von diesem Gerät trennen möchten?'; + + @override + String get login_repeaterLogin => 'Wiederholungseingang anmelden'; + + @override + String get login_roomLogin => 'Raum-Login'; + + @override + String get login_password => 'Passwort'; + + @override + String get login_enterPassword => 'Passwort eingeben'; + + @override + String get login_savePassword => 'Passwort speichern'; + + @override + String get login_savePasswordSubtitle => + 'Das Passwort wird auf diesem Gerät sicher gespeichert.'; + + @override + String get login_repeaterDescription => + 'Geben Sie das Repeater-Passwort ein, um auf Einstellungen und Status zuzugreifen.'; + + @override + String get login_roomDescription => + 'Geben Sie das Raumkennwort ein, um auf die Einstellungen und den Status zuzugreifen.'; + + @override + String get login_routing => 'Routen'; + + @override + String get login_routingMode => 'Routenmodus'; + + @override + String get login_autoUseSavedPath => + 'Automatisch (gespeicherten Pfad verwenden)'; + + @override + String get login_forceFloodMode => 'Zwangsgelände-Modus erzwingen'; + + @override + String get login_managePaths => 'Pfadverwaltung'; + + @override + String get login_login => 'Anmelden'; + + @override + String login_attempt(int current, int max) { + return 'Versuche $current/$max'; + } + + @override + String login_failed(String error) { + return 'Anmeldung fehlgeschlagen: $error'; + } + + @override + String get common_reload => 'Neu laden'; + + @override + String get common_clear => 'Löschen'; + + @override + String path_currentPath(String path) { + return 'Aktiger Pfad: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'Hops', + one: 'Hop', + ); + return 'Verwenden Sie $count $_temp0 Pfad'; + } + + @override + String get path_enterCustomPath => 'Gib Pfad an'; + + @override + String get path_currentPathLabel => 'Aktueller Pfad'; + + @override + String get path_hexPrefixInstructions => + 'Gib für jeden Hopfen 2-stellige Hex-Präfixe ein, getrennt durch Kommas.'; + + @override + String get path_hexPrefixExample => + 'Beispiel: A1,F2,3C (jeder Knoten verwendet den ersten Byte seines öffentlichen Schlüssels)'; + + @override + String get path_labelHexPrefixes => 'Pfad (Hex-Präfixe)'; + + @override + String get path_helperMaxHops => + 'Max 64 Sprünge. Jede Präfixe ist 2 Hexadezimalzeichen (1 Byte)'; + + @override + String get path_selectFromContacts => 'Oder wähle aus Kontakten aus:'; + + @override + String get path_noRepeatersFound => + 'Keine Repeater oder Raumserver gefunden.'; + + @override + String get path_customPathsRequire => + 'Benutzerdefinierte Pfade erfordern Zwischen-Hops, die Nachrichten weiterleiten können.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Ungültige Hexadezimal-Präfixe: $prefixes'; + } + + @override + String get path_tooLong => 'Pfad zu lang. Maximal 64 Hops erlaubt.'; + + @override + String get path_setPath => 'Pfad festlegen'; + + @override + String get repeater_management => 'Wiederholungselement-Verwaltung'; + + @override + String get repeater_managementTools => 'Verwaltungs-Tools'; + + @override + String get repeater_status => 'Status'; + + @override + String get repeater_statusSubtitle => + 'Status, Statistiken und Nachbarn anzeigen'; + + @override + String get repeater_telemetry => 'Telemetrie'; + + @override + String get repeater_telemetrySubtitle => + 'Sensordaten und Systemwerte anzeigen'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Sende Befehle an den Repeater'; + + @override + String get repeater_settings => 'Einstellungen'; + + @override + String get repeater_settingsSubtitle => + 'Wiederholungsparameter konfigurieren'; + + @override + String get repeater_statusTitle => 'Wiederholungszustand'; + + @override + String get repeater_routingMode => 'Routenmodus'; + + @override + String get repeater_autoUseSavedPath => + 'Automatisch (gespeicherten Pfad verwenden)'; + + @override + String get repeater_forceFloodMode => 'Zwangsgelände-Modus erzwingen'; + + @override + String get repeater_pathManagement => 'Pfadverwaltung'; + + @override + String get repeater_refresh => 'Aktualisieren'; + + @override + String get repeater_statusRequestTimeout => + 'Statusanfrage zeitweise fehlgeschlagen.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Fehler beim Laden des Status: $error'; + } + + @override + String get repeater_systemInformation => 'Systeminformation'; + + @override + String get repeater_battery => 'Akku'; + + @override + String get repeater_clockAtLogin => 'Uhr (bei Anmeldung)'; + + @override + String get repeater_uptime => 'Verfügbarkeit'; + + @override + String get repeater_queueLength => 'Warteschlangenlänge'; + + @override + String get repeater_debugFlags => 'Fehlerbehebungsoptionen'; + + @override + String get repeater_radioStatistics => 'Funk-Statistik'; + + @override + String get repeater_lastRssi => 'Letzter RSSI'; + + @override + String get repeater_lastSnr => 'Letzter SNR'; + + @override + String get repeater_noiseFloor => 'Rauschpegel'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Paketstatistiken'; + + @override + String get repeater_sent => 'Gesendet'; + + @override + String get repeater_received => 'Empfangen'; + + @override + String get repeater_duplicates => 'Duplikate'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days Tage ${hours}h ${minutes}m ${seconds}s'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Gesamt: $total, Flut: $flood, Direkt: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Gesamt: $total, Flut: $flood, Direkt: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Überflut: $flood, Direkt: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Gesamt: $total'; + } + + @override + String get repeater_settingsTitle => 'Wiederholungseinstellungen'; + + @override + String get repeater_basicSettings => 'Grundlegende Einstellungen'; + + @override + String get repeater_repeaterName => 'Wiederholungseintrag'; + + @override + String get repeater_repeaterNameHelper => 'Anzeigename für diesen Repeater'; + + @override + String get repeater_adminPassword => 'Admin-Passwort'; + + @override + String get repeater_adminPasswordHelper => 'Vollzugriffspasswort'; + + @override + String get repeater_guestPassword => 'Gast-Passwort'; + + @override + String get repeater_guestPasswordHelper => + 'Schreibgeschützter Zugriffspasswort'; + + @override + String get repeater_radioSettings => 'Funk Einstellungen'; + + @override + String get repeater_frequencyMhz => 'Frequenz (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Power'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Bandbreite'; + + @override + String get repeater_spreadingFactor => 'Verteilungsfaktor'; + + @override + String get repeater_codingRate => 'Programmierpauschale'; + + @override + String get repeater_locationSettings => 'Standort Einstellungen'; + + @override + String get repeater_latitude => 'Breitengrad'; + + @override + String get repeater_latitudeHelper => 'Dezimalgrad (z.B. 37,7749)'; + + @override + String get repeater_longitude => 'Längengrad'; + + @override + String get repeater_longitudeHelper => 'Dezimalgrad (z.B. -122,4194)'; + + @override + String get repeater_features => 'Funktionen'; + + @override + String get repeater_packetForwarding => 'Paketweiterleitung'; + + @override + String get repeater_packetForwardingSubtitle => + 'Aktivieren Sie den Repeater, um Pakete weiterzuleiten.'; + + @override + String get repeater_guestAccess => 'Gastzugriff'; + + @override + String get repeater_guestAccessSubtitle => + 'Gast-Zugriff mit beschränkten Rechten zulassen'; + + @override + String get repeater_privacyMode => 'Privatschutzzustand'; + + @override + String get repeater_privacyModeSubtitle => + 'Verstecken Sie Name/Ort in Anzeigen'; + + @override + String get repeater_advertisementSettings => 'Werbe Einstellungen'; + + @override + String get repeater_localAdvertInterval => 'Lokaler Werbeintervall'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes Minuten'; + } + + @override + String get repeater_floodAdvertInterval => 'Überschwemmungsanzeige-Intervall'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours Stunden'; + } + + @override + String get repeater_encryptedAdvertInterval => + 'Verschlüsselte Werbeintervall'; + + @override + String get repeater_dangerZone => 'Gefahrenzone'; + + @override + String get repeater_rebootRepeater => 'Neustart Repeater'; + + @override + String get repeater_rebootRepeaterSubtitle => + 'Wiederholen Sie das Repeater-Gerät.'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Sind Sie sicher, dass Sie diesen Repeater neu starten möchten?'; + + @override + String get repeater_regenerateIdentityKey => + 'Schlüssel für die Identitätswiederherstellung'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Neuen öffentlichen/privaten Schlüsselpaar generieren'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'Dies generiert eine neue Identität für den Repeater. Fortfahren?'; + + @override + String get repeater_eraseFileSystem => 'Dateisystem löschen'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Formatiere die Repeater-Dateisystemdatei'; + + @override + String get repeater_eraseFileSystemConfirm => + 'WARNUNG: Dies löscht alle Daten auf dem Repeater. Dies kann nicht rückgängig gemacht werden!'; + + @override + String get repeater_eraseSerialOnly => + 'Löschen ist nur über die serielle Konsole möglich.'; + + @override + String repeater_commandSent(String command) { + return 'Befehl gesendet: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Fehler beim Senden des Befehls: $error'; + } + + @override + String get repeater_confirm => 'Bestätigen'; + + @override + String get repeater_settingsSaved => 'Einstellungen erfolgreich gespeichert'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Fehler beim Speichern der Einstellungen: $error'; + } + + @override + String get repeater_refreshBasicSettings => + 'Grundlegende Einstellungen aktualisieren'; + + @override + String get repeater_refreshRadioSettings => + 'Radio-Einstellungen aktualisieren'; + + @override + String get repeater_refreshTxPower => 'Batterie-Strom aktualisieren'; + + @override + String get repeater_refreshLocationSettings => + 'Aktualisieren Sie die Standort Einstellungen'; + + @override + String get repeater_refreshPacketForwarding => + 'Aktualisieren Paketweiterleitung'; + + @override + String get repeater_refreshGuestAccess => 'Aktualisieren Sie den Gastzugriff'; + + @override + String get repeater_refreshPrivacyMode => + 'Wiederherstellen des Datenschutzzustands'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Aktualisieren Sie die Werbe Einstellungen'; + + @override + String repeater_refreshed(String label) { + return '$label wurde aktualisiert'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Fehler beim Aktualisieren von $label'; + } + + @override + String get repeater_cliTitle => 'Wiederholung CLI'; + + @override + String get repeater_debugNextCommand => 'Fehlersuche Nächster Befehl'; + + @override + String get repeater_commandHelp => 'Hilfe'; + + @override + String get repeater_clearHistory => 'Löschung der Historie'; + + @override + String get repeater_noCommandsSent => 'Noch keine Befehle gesendet.'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Geben Sie einen Befehl unten ein oder verwenden Sie Schnellbefehle'; + + @override + String get repeater_enterCommandHint => 'Geben Sie den Befehl ein...'; + + @override + String get repeater_previousCommand => 'Vorhergehende Aktion'; + + @override + String get repeater_nextCommand => 'Nächste Aktion'; + + @override + String get repeater_enterCommandFirst => 'Geben Sie zuerst einen Befehl ein'; + + @override + String get repeater_cliCommandFrameTitle => 'CLI-Befehlsfenster'; + + @override + String repeater_cliCommandError(String error) { + return 'Fehler: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Name erhalten'; + + @override + String get repeater_cliQuickGetRadio => 'Radio empfangen'; + + @override + String get repeater_cliQuickGetTx => 'Erhalte TX'; + + @override + String get repeater_cliQuickNeighbors => 'Nachbarn'; + + @override + String get repeater_cliQuickVersion => 'Version'; + + @override + String get repeater_cliQuickAdvertise => 'Werben'; + + @override + String get repeater_cliQuickClock => 'Uhr'; + + @override + String get repeater_cliHelpAdvert => 'Sendet ein Werbepaket'; + + @override + String get repeater_cliHelpReboot => + 'Startet das Gerät neu. (Beachten Sie, dass es möglicherweise zu einer \'Timeout\'-Situation kommt, was normal ist.)'; + + @override + String get repeater_cliHelpClock => + 'Zeigt die aktuelle Uhrzeit pro Gerät an.'; + + @override + String get repeater_cliHelpPassword => + 'Legt ein neues Administrator-Passwort für das Gerät fest.'; + + @override + String get repeater_cliHelpVersion => + 'Zeigt die Geräteversion und das Datum des Firmware-Builds an.'; + + @override + String get repeater_cliHelpClearStats => + 'Setzt verschiedene Statistikkalkulate auf Null zurück.'; + + @override + String get repeater_cliHelpSetAf => 'Legt den Luftzeitfaktor fest.'; + + @override + String get repeater_cliHelpSetTx => + 'Legt die LoRa-Übertragungspower in dBm (bezogen auf 1 Watt) fest. (Neustart erforderlich, um die Änderungen anzuwenden)'; + + @override + String get repeater_cliHelpSetRepeat => + 'Aktiviert oder deaktiviert die Repeater-Rolle für diesen Knoten.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Raumspeicher) Wenn \'an\', dann wird die Anmeldung mit einem leeren Passwort erlaubt sein, aber kann nicht in den Raum geschickt werden. (nur lesen möglich).'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Legt die maximale Anzahl an Hops für Pakete der eingehenden Flut (wenn >= max, wird das Paket nicht weitergeleitet)'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Legt den Interferenzeniveau (in dB) fest. Der Standardwert ist 14. Auf 0 setzen, um die Erkennung von Kanalinterferenzen zu deaktivieren.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Legt das Intervall für das Zurücksetzen des Auto Gain Controllers fest. Auf 0 setzen, um die Funktion zu deaktivieren.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Aktiviert oder deaktiviert die Funktion \'Doppel-ACKs\'.'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Legt das Timer-Intervall in Minuten fest, um ein lokales (ohne-Weiterleitung) Werbe-Paket zu senden. Auf 0 setzen, um die Funktion zu deaktivieren.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Legt das Timer-Intervall in Stunden für den Versand eines Flut-Werbungspakets fest. Auf 0 setzen, um es zu deaktivieren.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Legt/aktualisiert das Gastpasswort fest. (für Repeater können Gast-Logins die \"Get Stats\"-Anfrage senden)'; + + @override + String get repeater_cliHelpSetName => 'Legt den Anzeigenamen fest.'; + + @override + String get repeater_cliHelpSetLat => + 'Legt die Breitengrad-Angabe der Werbekarte fest. (dezimale Grad)'; + + @override + String get repeater_cliHelpSetLon => + 'Legt die Längengrade der Werbe-Map fest. (dezimale Grad)'; + + @override + String get repeater_cliHelpSetRadio => + 'Legt komplett neue Radio-Parameter fest und speichert diese als Präferenzen. Benötigt einen \"Reboot\"-Befehl, um sie anzuwenden.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Sets (experimentell) als Basis (muss > 1 sein für den Effekt) zur Anwendung einer leichten Verzögerung bei empfangenen Paketen, basierend auf Signalstärke/Punktzahl. Auf 0 setzen, um die Funktion zu deaktivieren.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Legt einen Faktor fest, der mit der Zeit bei voller Zuluft für ein Flood-Mode-Paket und mit einem zufälligen Slot-System multipliziert wird, um dessen Weiterleitung zu verzögern (um Kollisionen zu vermeiden).'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Ähnlich wie txdelay, aber zum Anwenden einer zufälligen Verzögerung bei der Weiterleitung von Direktmodus-Paketen.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => + 'Brücke aktivieren/deaktivieren.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Setze Verzögerung vor erneuter Übertragung von Paketen.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Wählen Sie, ob die Brücke empfangene oder gesendete Pakete erneut übertragen soll.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Setze die serielle Link-Baudrate für RS232-Brücken.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Richte das Espnow-Brücken-Geheimnis ein.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Legt einen benutzerdefinierten Faktor zur Anpassung der gemeldeten Batteriewirkspannung fest (nur auf ausgewählten Boards unterstützt).'; + + @override + String get repeater_cliHelpTempRadio => + 'Legt vorübergehende Funkparameter für die angegebene Anzahl von Minuten fest und kehrt anschließend zu den ursprünglichen Funkparametern zurück (wird nicht in den Einstellungen gespeichert).'; + + @override + String get repeater_cliHelpSetPerm => + 'Ändert die ACL. Entfernt das passende Eintragen (durch Pubkey-Präfix), wenn \"permissions\" auf 0 steht. Fügt ein neues Eintragen hinzu, wenn die Pubkey-Hex-Länge vollständig ist und nicht bereits in der ACL vorhanden ist. Aktualisiert das Eintragen anhand des übereinstimmenden Pubkey-Präfix. Berechtigungsbits variieren je nach Firmware-Rolle, aber die unteren 2 Bits sind: 0 (Gast), 1 (Nur Lesen), 2 (Lesen/Schreiben), 3 (Admin)'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Ruft Brückentyp none, rs232, espnow ab.'; + + @override + String get repeater_cliHelpLogStart => + 'Beginnt die Paketprotokollierung in das Dateisystem.'; + + @override + String get repeater_cliHelpLogStop => + 'Stoppt das Paketprotokollieren in das Dateisystem.'; + + @override + String get repeater_cliHelpLogErase => + 'Löscht die Paketprotokolle aus dem Dateisystem.'; + + @override + String get repeater_cliHelpNeighbors => + 'Zeigt eine Liste anderer Repeater-Knoten an, die über Zero-Hop-Werbung gehört wurden. Jede Zeile ist id-prefix-hex:timestamp:snr-times-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Entfernt das erste übereinstimmende Element (über Pubkey-Präfix (hex)) aus der Liste der Nachbarn.'; + + @override + String get repeater_cliHelpRegion => + '(Serien nur) Listet alle definierten Regionen und aktuelle Hochwassermissungen auf.'; + + @override + String get repeater_cliHelpRegionLoad => + 'Hinweis: Dies ist ein spezieller Mehrbefehl-Aufruf. Jeder nachfolgende Befehl ist ein Regionsname (eingedruckt mit Leerzeichen zur Angabe der übergeordneten Hierarchie, mit mindestens einem Leerzeichen). Beendet durch das Senden einer Leerzeile/des Befehls.'; + + @override + String get repeater_cliHelpRegionGet => + 'Sucht die Region mit dem gegebenen Namenspräfix (oder \"\\\" für den globalen Scope) und antwortet mit \"-> region-name (parent-name) \'F\'\".'; + + @override + String get repeater_cliHelpRegionPut => + 'Fügt eine Region-Definition mit dem angegebenen Namen hinzu oder aktualisiert diese.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Löscht eine Regiondefinition mit dem angegebenen Namen. (muss genau übereinstimmen und keine Kindregionen haben)'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Legt die \'Flut\'-Berechtigung für die angegebene Region fest. (\'\' für den globalen/legacy-Bereich)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Entfernt die \"F\"lood-Berechtigung für die angegebene Region. (ANMERKUNG: in dieser Phase wird nicht empfohlen, dies auf dem globalen/legacy-Bereich zu verwenden!!)'; + + @override + String get repeater_cliHelpRegionHome => + 'Antwortet mit der aktuellen \'Home\'-Region. (Hinweis wurde bisher nirgendwo angewendet, für zukünftige Zwecke reserviert)'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Legt die \'Home\'-Region fest.'; + + @override + String get repeater_cliHelpRegionSave => + 'Speichert die Regionenliste/Karte in den Speicher.'; + + @override + String get repeater_cliHelpGps => + 'Zeigt GPS-Status an. Wenn GPS deaktiviert ist, antwortet es nur mit \"aus\", wenn es eingeschaltet ist, antwortet es mit \"an\", \"Status\", \"Fix\" und Satellitenanzahl.'; + + @override + String get repeater_cliHelpGpsOnOff => 'Schaltet die GPS-Leistung ein/aus.'; + + @override + String get repeater_cliHelpGpsSync => + 'Synchronisiert die Knotenzeit mit der GPS-Uhr.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Setze die Position des Knotens auf GPS-Koordinaten und speichere die Präferenzen.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Gibt Konfiguration für die Standortanzeige des Knotens:\n- none: Standort nicht in Anzeigen einbeziehen\n- share: GPS-Standort teilen (von SensorManager)\n- prefs: Standort aus Einstellungen anzeigen'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Legt die Standort-Anzeigekonfiguration fest.'; + + @override + String get repeater_commandsListTitle => 'Befehlsliste'; + + @override + String get repeater_commandsListNote => + 'ACHTUNG: Für die verschiedenen „set ...“-Befehle gibt es auch einen „get ...“-Befehl.'; + + @override + String get repeater_general => 'Allgemein'; + + @override + String get repeater_settingsCategory => 'Einstellungen'; + + @override + String get repeater_bridge => 'Brücke'; + + @override + String get repeater_logging => 'Protokollierung'; + + @override + String get repeater_neighborsRepeaterOnly => 'Nachbarn (nur Repeater)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Regionenverwaltung (nur Repeater)'; + + @override + String get repeater_regionNote => + 'Region-Befehle wurden eingeführt, um Region-Definitionen und Berechtigungen zu verwalten.'; + + @override + String get repeater_gpsManagement => 'GPS-Verwaltung'; + + @override + String get repeater_gpsNote => + 'Der GPS-Befehl wurde eingeführt, um Standortbezogene Themen zu verwalten.'; + + @override + String get telemetry_receivedData => 'Empfangene Telemetriedaten'; + + @override + String get telemetry_requestTimeout => + 'Telemetry-Anfrage hat zu lange gedauert.'; + + @override + String telemetry_errorLoading(String error) { + return 'Fehler beim Laden der Telemetrie: $error'; + } + + @override + String get telemetry_noData => 'Keine Telemetriedaten verfügbar.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Kanal $channel'; + } + + @override + String get telemetry_batteryLabel => 'Akku'; + + @override + String get telemetry_voltageLabel => 'Spannung'; + + @override + String get telemetry_mcuTemperatureLabel => 'MCU Temperatur'; + + @override + String get telemetry_temperatureLabel => 'Temperatur'; + + @override + String get telemetry_currentLabel => 'Aktuell'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '$volts Volt'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Paketpfad'; + + @override + String get channelPath_viewMap => 'Karte anzeigen'; + + @override + String get channelPath_otherObservedPaths => 'Sonstige beobachtete Pfade'; + + @override + String get channelPath_repeaterHops => 'Wiederholungs-Sprünge'; + + @override + String get channelPath_noHopDetails => + 'Die Detailangaben für dieses Paket sind nicht verfügbar.'; + + @override + String get channelPath_messageDetails => 'Nachrichtsdetails'; + + @override + String get channelPath_senderLabel => 'Sender'; + + @override + String get channelPath_timeLabel => 'Zeit'; + + @override + String get channelPath_repeatsLabel => 'Wiederholung'; + + @override + String channelPath_pathLabel(int index) { + return 'Pfad $index'; + } + + @override + String get channelPath_observedLabel => 'Beobachtet'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Beobachteter Pfad $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'Keine Standortdaten'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Unbekannt'; + + @override + String get channelPath_floodPath => 'Überschwemmung'; + + @override + String get channelPath_directPath => 'Direkt'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 von $total Sprüngen'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed von $total Sprüngen'; + } + + @override + String get channelPath_mapTitle => 'Pfadkarte'; + + @override + String get channelPath_noRepeaterLocations => + 'Für diesen Pfad stehen keine Repeater-Positionen zur Verfügung.'; + + @override + String channelPath_primaryPath(int index) { + return 'Pfad $index (Primär)'; + } + + @override + String get channelPath_pathLabelTitle => 'Pfad'; + + @override + String get channelPath_observedPathHeader => 'Beobachteter Pfad'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'Keine Informationen zu dieser Paketroute verfügbar.'; + + @override + String get channelPath_unknownRepeater => 'Unbekannter Repeater'; + + @override + String get listFilter_tooltip => 'Filteren und sortieren'; + + @override + String get listFilter_sortBy => 'Sortiere nach'; + + @override + String get listFilter_latestMessages => 'Letzte Nachrichten'; + + @override + String get listFilter_heardRecently => 'Hörte kürzlich'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Filtere'; + + @override + String get listFilter_all => 'Alle'; + + @override + String get listFilter_users => 'Benutzer'; + + @override + String get listFilter_repeaters => 'Wiederholer'; + + @override + String get listFilter_roomServers => 'Raumserver'; + + @override + String get listFilter_unreadOnly => 'Nur nicht gelesen'; + + @override + String get listFilter_newGroup => 'Neue Gruppe'; +} diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart new file mode 100644 index 0000000..9e04923 --- /dev/null +++ b/lib/l10n/app_localizations_en.dart @@ -0,0 +1,2357 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for English (`en`). +class AppLocalizationsEn extends AppLocalizations { + AppLocalizationsEn([String locale = 'en']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Contacts'; + + @override + String get nav_channels => 'Channels'; + + @override + String get nav_map => 'Map'; + + @override + String get common_cancel => 'Cancel'; + + @override + String get common_connect => 'Connect'; + + @override + String get common_unknownDevice => 'Unknown Device'; + + @override + String get common_save => 'Save'; + + @override + String get common_delete => 'Delete'; + + @override + String get common_close => 'Close'; + + @override + String get common_edit => 'Edit'; + + @override + String get common_add => 'Add'; + + @override + String get common_settings => 'Settings'; + + @override + String get common_disconnect => 'Disconnect'; + + @override + String get common_connected => 'Connected'; + + @override + String get common_disconnected => 'Disconnected'; + + @override + String get common_create => 'Create'; + + @override + String get common_continue => 'Continue'; + + @override + String get common_share => 'Share'; + + @override + String get common_copy => 'Copy'; + + @override + String get common_retry => 'Retry'; + + @override + String get common_hide => 'Hide'; + + @override + String get common_remove => 'Remove'; + + @override + String get common_enable => 'Enable'; + + @override + String get common_disable => 'Disable'; + + @override + String get common_reboot => 'Reboot'; + + @override + String get common_loading => 'Loading...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Scanning for devices...'; + + @override + String get scanner_connecting => 'Connecting...'; + + @override + String get scanner_disconnecting => 'Disconnecting...'; + + @override + String get scanner_notConnected => 'Not connected'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Connected to $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Searching for MeshCore devices...'; + + @override + String get scanner_tapToScan => 'Tap Scan to find MeshCore devices'; + + @override + String scanner_connectionFailed(String error) { + return 'Connection failed: $error'; + } + + @override + String get scanner_stop => 'Stop'; + + @override + String get scanner_scan => 'Scan'; + + @override + String get device_quickSwitch => 'Quick switch'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Settings'; + + @override + String get settings_deviceInfo => 'Device Info'; + + @override + String get settings_appSettings => 'App Settings'; + + @override + String get settings_appSettingsSubtitle => + 'Notifications, messaging, and map preferences'; + + @override + String get settings_nodeSettings => 'Node Settings'; + + @override + String get settings_nodeName => 'Node Name'; + + @override + String get settings_nodeNameNotSet => 'Not set'; + + @override + String get settings_nodeNameHint => 'Enter node name'; + + @override + String get settings_nodeNameUpdated => 'Name updated'; + + @override + String get settings_radioSettings => 'Radio Settings'; + + @override + String get settings_radioSettingsSubtitle => + 'Frequency, power, spreading factor'; + + @override + String get settings_radioSettingsUpdated => 'Radio settings updated'; + + @override + String get settings_location => 'Location'; + + @override + String get settings_locationSubtitle => 'GPS coordinates'; + + @override + String get settings_locationUpdated => 'Location updated'; + + @override + String get settings_locationBothRequired => + 'Enter both latitude and longitude.'; + + @override + String get settings_locationInvalid => 'Invalid latitude or longitude.'; + + @override + String get settings_latitude => 'Latitude'; + + @override + String get settings_longitude => 'Longitude'; + + @override + String get settings_privacyMode => 'Privacy Mode'; + + @override + String get settings_privacyModeSubtitle => + 'Hide name/location in advertisements'; + + @override + String get settings_privacyModeToggle => + 'Toggle privacy mode to hide your name and location in advertisements.'; + + @override + String get settings_privacyModeEnabled => 'Privacy mode enabled'; + + @override + String get settings_privacyModeDisabled => 'Privacy mode disabled'; + + @override + String get settings_actions => 'Actions'; + + @override + String get settings_sendAdvertisement => 'Send Advertisement'; + + @override + String get settings_sendAdvertisementSubtitle => 'Broadcast presence now'; + + @override + String get settings_advertisementSent => 'Advertisement sent'; + + @override + String get settings_syncTime => 'Sync Time'; + + @override + String get settings_syncTimeSubtitle => 'Set device clock to phone time'; + + @override + String get settings_timeSynchronized => 'Time synchronized'; + + @override + String get settings_refreshContacts => 'Refresh Contacts'; + + @override + String get settings_refreshContactsSubtitle => + 'Reload contact list from device'; + + @override + String get settings_rebootDevice => 'Reboot Device'; + + @override + String get settings_rebootDeviceSubtitle => 'Restart the MeshCore device'; + + @override + String get settings_rebootDeviceConfirm => + 'Are you sure you want to reboot the device? You will be disconnected.'; + + @override + String get settings_debug => 'Debug'; + + @override + String get settings_bleDebugLog => 'BLE Debug Log'; + + @override + String get settings_bleDebugLogSubtitle => + 'BLE commands, responses, and raw data'; + + @override + String get settings_appDebugLog => 'App Debug Log'; + + @override + String get settings_appDebugLogSubtitle => 'Application debug messages'; + + @override + String get settings_about => 'About'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => '2026 MeshCore Open Source Project'; + + @override + String get settings_aboutDescription => + 'An open-source Flutter client for MeshCore LoRa mesh networking devices.'; + + @override + String get settings_infoName => 'Name'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'Status'; + + @override + String get settings_infoBattery => 'Battery'; + + @override + String get settings_infoPublicKey => 'Public Key'; + + @override + String get settings_infoContactsCount => 'Contacts Count'; + + @override + String get settings_infoChannelCount => 'Channel Count'; + + @override + String get settings_presets => 'Presets'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Frequency (MHz)'; + + @override + String get settings_frequencyHelper => '300.0 - 2500.0'; + + @override + String get settings_frequencyInvalid => 'Invalid frequency (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Bandwidth'; + + @override + String get settings_spreadingFactor => 'Spreading Factor'; + + @override + String get settings_codingRate => 'Coding Rate'; + + @override + String get settings_txPower => 'TX Power (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Invalid TX power (0-22 dBm)'; + + @override + String get settings_longRange => 'Long Range'; + + @override + String get settings_fastSpeed => 'Fast Speed'; + + @override + String settings_error(String message) { + return 'Error: $message'; + } + + @override + String get appSettings_title => 'App Settings'; + + @override + String get appSettings_appearance => 'Appearance'; + + @override + String get appSettings_theme => 'Theme'; + + @override + String get appSettings_themeSystem => 'System default'; + + @override + String get appSettings_themeLight => 'Light'; + + @override + String get appSettings_themeDark => 'Dark'; + + @override + String get appSettings_language => 'Language'; + + @override + String get appSettings_languageSystem => 'System default'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Notifications'; + + @override + String get appSettings_enableNotifications => 'Enable Notifications'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Receive notifications for messages and adverts'; + + @override + String get appSettings_notificationPermissionDenied => + 'Notification permission denied'; + + @override + String get appSettings_notificationsEnabled => 'Notifications enabled'; + + @override + String get appSettings_notificationsDisabled => 'Notifications disabled'; + + @override + String get appSettings_messageNotifications => 'Message Notifications'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Show notification when receiving new messages'; + + @override + String get appSettings_channelMessageNotifications => + 'Channel Message Notifications'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Show notification when receiving channel messages'; + + @override + String get appSettings_advertisementNotifications => + 'Advertisement Notifications'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Show notification when new nodes are discovered'; + + @override + String get appSettings_messaging => 'Messaging'; + + @override + String get appSettings_clearPathOnMaxRetry => 'Clear Path on Max Retry'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Reset contact path after 5 failed send attempts'; + + @override + String get appSettings_pathsWillBeCleared => + 'Paths will be cleared after 5 failed retries'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Paths will not be auto-cleared'; + + @override + String get appSettings_autoRouteRotation => 'Auto Route Rotation'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Cycle between best paths and flood mode'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Auto route rotation enabled'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Auto route rotation disabled'; + + @override + String get appSettings_battery => 'Battery'; + + @override + String get appSettings_batteryChemistry => 'Battery Chemistry'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Set per device ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Connect to a device to choose'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3.0-4.2V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2.6-3.65V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3.0-4.2V)'; + + @override + String get appSettings_mapDisplay => 'Map Display'; + + @override + String get appSettings_showRepeaters => 'Show Repeaters'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Display repeater nodes on the map'; + + @override + String get appSettings_showChatNodes => 'Show Chat Nodes'; + + @override + String get appSettings_showChatNodesSubtitle => + 'Display chat nodes on the map'; + + @override + String get appSettings_showOtherNodes => 'Show Other Nodes'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Display other node types on the map'; + + @override + String get appSettings_timeFilter => 'Time Filter'; + + @override + String get appSettings_timeFilterShowAll => 'Show all nodes'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Show nodes from last $hours hours'; + } + + @override + String get appSettings_mapTimeFilter => 'Map Time Filter'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Show nodes discovered within:'; + + @override + String get appSettings_allTime => 'All time'; + + @override + String get appSettings_lastHour => 'Last hour'; + + @override + String get appSettings_last6Hours => 'Last 6 hours'; + + @override + String get appSettings_last24Hours => 'Last 24 hours'; + + @override + String get appSettings_lastWeek => 'Last week'; + + @override + String get appSettings_offlineMapCache => 'Offline Map Cache'; + + @override + String get appSettings_noAreaSelected => 'No area selected'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Area selected (zoom $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Debug'; + + @override + String get appSettings_appDebugLogging => 'App Debug Logging'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Log app debug messages for troubleshooting'; + + @override + String get appSettings_appDebugLoggingEnabled => 'App debug logging enabled'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'App debug logging disabled'; + + @override + String get contacts_title => 'Contacts'; + + @override + String get contacts_noContacts => 'No contacts yet'; + + @override + String get contacts_contactsWillAppear => + 'Contacts will appear when devices advertise'; + + @override + String get contacts_searchContacts => 'Search contacts...'; + + @override + String get contacts_noUnreadContacts => 'No unread contacts'; + + @override + String get contacts_noContactsFound => 'No contacts or groups found'; + + @override + String get contacts_deleteContact => 'Delete Contact'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Remove $contactName from contacts?'; + } + + @override + String get contacts_manageRepeater => 'Manage Repeater'; + + @override + String get contacts_roomLogin => 'Room Login'; + + @override + String get contacts_openChat => 'Open Chat'; + + @override + String get contacts_editGroup => 'Edit Group'; + + @override + String get contacts_deleteGroup => 'Delete Group'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Remove \"$groupName\"?'; + } + + @override + String get contacts_newGroup => 'New Group'; + + @override + String get contacts_groupName => 'Group name'; + + @override + String get contacts_groupNameRequired => 'Group name is required'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'Group \"$name\" already exists'; + } + + @override + String get contacts_filterContacts => 'Filter contacts...'; + + @override + String get contacts_noContactsMatchFilter => 'No contacts match your filter'; + + @override + String get contacts_noMembers => 'No members'; + + @override + String get contacts_lastSeenNow => 'Last seen now'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Last seen $minutes mins ago'; + } + + @override + String get contacts_lastSeenHourAgo => 'Last seen 1 hour ago'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Last seen $hours hours ago'; + } + + @override + String get contacts_lastSeenDayAgo => 'Last seen 1 day ago'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Last seen $days days ago'; + } + + @override + String get channels_title => 'Channels'; + + @override + String get channels_noChannelsConfigured => 'No channels configured'; + + @override + String get channels_addPublicChannel => 'Add Public Channel'; + + @override + String get channels_searchChannels => 'Search channels...'; + + @override + String get channels_noChannelsFound => 'No channels found'; + + @override + String channels_channelIndex(int index) { + return 'Channel $index'; + } + + @override + String get channels_hashtagChannel => 'Hashtag channel'; + + @override + String get channels_public => 'Public'; + + @override + String get channels_private => 'Private'; + + @override + String get channels_publicChannel => 'Public channel'; + + @override + String get channels_privateChannel => 'Private channel'; + + @override + String get channels_editChannel => 'Edit channel'; + + @override + String get channels_deleteChannel => 'Delete channel'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Delete \"$name\"? This cannot be undone.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Channel \"$name\" deleted'; + } + + @override + String get channels_addChannel => 'Add Channel'; + + @override + String get channels_channelIndexLabel => 'Channel Index'; + + @override + String get channels_channelName => 'Channel Name'; + + @override + String get channels_usePublicChannel => 'Use Public Channel'; + + @override + String get channels_standardPublicPsk => 'Standard public PSK'; + + @override + String get channels_pskHex => 'PSK (Hex)'; + + @override + String get channels_generateRandomPsk => 'Generate random PSK'; + + @override + String get channels_enterChannelName => 'Please enter a channel name'; + + @override + String get channels_pskMustBe32Hex => 'PSK must be 32 hex characters'; + + @override + String channels_channelAdded(String name) { + return 'Channel \"$name\" added'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Edit Channel $index'; + } + + @override + String get channels_smazCompression => 'SMAZ compression'; + + @override + String channels_channelUpdated(String name) { + return 'Channel \"$name\" updated'; + } + + @override + String get channels_publicChannelAdded => 'Public channel added'; + + @override + String get channels_sortBy => 'Sort by'; + + @override + String get channels_sortManual => 'Manual'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => 'Latest messages'; + + @override + String get channels_sortUnread => 'Unread'; + + @override + String get chat_noMessages => 'No messages yet'; + + @override + String get chat_sendMessageToStart => 'Send a message to get started'; + + @override + String get chat_originalMessageNotFound => 'Original message not found'; + + @override + String chat_replyingTo(String name) { + return 'Replying to $name'; + } + + @override + String chat_replyTo(String name) { + return 'Reply to $name'; + } + + @override + String get chat_location => 'Location'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Send a message to $contactName'; + } + + @override + String get chat_typeMessage => 'Type a message...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Message too long (max $maxBytes bytes).'; + } + + @override + String get chat_messageCopied => 'Message copied'; + + @override + String get chat_messageDeleted => 'Message deleted'; + + @override + String get chat_retryingMessage => 'Retrying message'; + + @override + String chat_retryCount(int current, int max) { + return 'Retry $current/$max'; + } + + @override + String get chat_sendGif => 'Send GIF'; + + @override + String get chat_reply => 'Reply'; + + @override + String get chat_addReaction => 'Add Reaction'; + + @override + String get chat_me => 'Me'; + + @override + String get emojiCategorySmileys => 'Smileys'; + + @override + String get emojiCategoryGestures => 'Gestures'; + + @override + String get emojiCategoryHearts => 'Hearts'; + + @override + String get emojiCategoryObjects => 'Objects'; + + @override + String get gifPicker_title => 'Choose a GIF'; + + @override + String get gifPicker_searchHint => 'Search GIFs...'; + + @override + String get gifPicker_poweredBy => 'Powered by GIPHY'; + + @override + String get gifPicker_noGifsFound => 'No GIFs found'; + + @override + String get gifPicker_failedLoad => 'Failed to load GIFs'; + + @override + String get gifPicker_failedSearch => 'Failed to search GIFs'; + + @override + String get gifPicker_noInternet => 'No internet connection'; + + @override + String get debugLog_appTitle => 'App Debug Log'; + + @override + String get debugLog_bleTitle => 'BLE Debug Log'; + + @override + String get debugLog_copyLog => 'Copy log'; + + @override + String get debugLog_clearLog => 'Clear log'; + + @override + String get debugLog_copied => 'Debug log copied'; + + @override + String get debugLog_bleCopied => 'BLE log copied'; + + @override + String get debugLog_noEntries => 'No debug logs yet'; + + @override + String get debugLog_enableInSettings => + 'Enable app debug logging in settings'; + + @override + String get debugLog_frames => 'Frames'; + + @override + String get debugLog_rawLogRx => 'Raw Log-RX'; + + @override + String get debugLog_noBleActivity => 'No BLE activity yet'; + + @override + String debugFrame_length(int count) { + return 'Frame Length: $count bytes'; + } + + @override + String debugFrame_command(String value) { + return 'Command: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Text Message Frame:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Destination PubKey: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Timestamp: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Flags: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Text Type: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Plain'; + + @override + String debugFrame_text(String text) { + return '- Text: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Hex Dump:'; + + @override + String get chat_pathManagement => 'Path Management'; + + @override + String get chat_routingMode => 'Routing mode'; + + @override + String get chat_autoUseSavedPath => 'Auto (use saved path)'; + + @override + String get chat_forceFloodMode => 'Force Flood Mode'; + + @override + String get chat_recentAckPaths => 'Recent ACK Paths (tap to use):'; + + @override + String get chat_pathHistoryFull => + 'Path history is full. Remove entries to add new ones.'; + + @override + String get chat_hopSingular => 'hop'; + + @override + String get chat_hopPlural => 'hops'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'successes'; + + @override + String get chat_removePath => 'Remove path'; + + @override + String get chat_noPathHistoryYet => + 'No path history yet.\nSend a message to discover paths.'; + + @override + String get chat_pathActions => 'Path Actions:'; + + @override + String get chat_setCustomPath => 'Set Custom Path'; + + @override + String get chat_setCustomPathSubtitle => 'Manually specify routing path'; + + @override + String get chat_clearPath => 'Clear Path'; + + @override + String get chat_clearPathSubtitle => 'Force rediscovery on next send'; + + @override + String get chat_pathCleared => + 'Path cleared. Next message will rediscover route.'; + + @override + String get chat_floodModeSubtitle => 'Use routing toggle in app bar'; + + @override + String get chat_floodModeEnabled => + 'Flood mode enabled. Toggle back via routing icon in app bar.'; + + @override + String get chat_fullPath => 'Full Path'; + + @override + String get chat_pathDetailsNotAvailable => + 'Path details not available yet. Try sending a message to refresh.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Path set: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => 'Saved locally. Connect to sync.'; + + @override + String get chat_pathDeviceConfirmed => 'Device confirmed.'; + + @override + String get chat_pathDeviceNotConfirmed => 'Device not confirmed yet.'; + + @override + String get chat_type => 'Type'; + + @override + String get chat_path => 'Path'; + + @override + String get chat_publicKey => 'Public Key'; + + @override + String get chat_compressOutgoingMessages => 'Compress outgoing messages'; + + @override + String get chat_floodForced => 'Flood (forced)'; + + @override + String get chat_directForced => 'Direct (forced)'; + + @override + String chat_hopsForced(int count) { + return '$count hops (forced)'; + } + + @override + String get chat_floodAuto => 'Flood (auto)'; + + @override + String get chat_direct => 'Direct'; + + @override + String get chat_poiShared => 'POI Shared'; + + @override + String chat_unread(int count) { + return 'Unread: $count'; + } + + @override + String get map_title => 'Node Map'; + + @override + String get map_noNodesWithLocation => 'No nodes with location data'; + + @override + String get map_nodesNeedGps => + 'Nodes need to share their GPS coordinates\nto appear on the map'; + + @override + String map_nodesCount(int count) { + return 'Nodes: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Pins: $count'; + } + + @override + String get map_chat => 'Chat'; + + @override + String get map_repeater => 'Repeater'; + + @override + String get map_room => 'Room'; + + @override + String get map_sensor => 'Sensor'; + + @override + String get map_pinDm => 'Pin (DM)'; + + @override + String get map_pinPrivate => 'Pin (Private)'; + + @override + String get map_pinPublic => 'Pin (Public)'; + + @override + String get map_lastSeen => 'Last Seen'; + + @override + String get map_disconnectConfirm => + 'Are you sure you want to disconnect from this device?'; + + @override + String get map_from => 'From'; + + @override + String get map_source => 'Source'; + + @override + String get map_flags => 'Flags'; + + @override + String get map_shareMarkerHere => 'Share marker here'; + + @override + String get map_pinLabel => 'Pin label'; + + @override + String get map_label => 'Label'; + + @override + String get map_pointOfInterest => 'Point of interest'; + + @override + String get map_sendToContact => 'Send to contact'; + + @override + String get map_sendToChannel => 'Send to channel'; + + @override + String get map_noChannelsAvailable => 'No channels available'; + + @override + String get map_publicLocationShare => 'Public location share'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'You are about to share a location in $channelLabel. This channel is public and anyone with the PSK can see it.'; + } + + @override + String get map_connectToShareMarkers => + 'Connect to a device to share markers'; + + @override + String get map_filterNodes => 'Filter Nodes'; + + @override + String get map_nodeTypes => 'Node Types'; + + @override + String get map_chatNodes => 'Chat Nodes'; + + @override + String get map_repeaters => 'Repeaters'; + + @override + String get map_otherNodes => 'Other Nodes'; + + @override + String get map_keyPrefix => 'Key Prefix'; + + @override + String get map_filterByKeyPrefix => 'Filter by key prefix'; + + @override + String get map_publicKeyPrefix => 'Public key prefix'; + + @override + String get map_markers => 'Markers'; + + @override + String get map_showSharedMarkers => 'Show shared markers'; + + @override + String get map_lastSeenTime => 'Last Seen Time'; + + @override + String get map_sharedPin => 'Shared pin'; + + @override + String get map_joinRoom => 'Join Room'; + + @override + String get map_manageRepeater => 'Manage Repeater'; + + @override + String get mapCache_title => 'Offline Map Cache'; + + @override + String get mapCache_selectAreaFirst => 'Select an area to cache first'; + + @override + String get mapCache_noTilesToDownload => 'No tiles to download for this area'; + + @override + String get mapCache_downloadTilesTitle => 'Download tiles'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Download $count tiles for offline use?'; + } + + @override + String get mapCache_downloadAction => 'Download'; + + @override + String mapCache_cachedTiles(int count) { + return 'Cached $count tiles'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Cached $downloaded tiles ($failed failed)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => 'Clear offline cache'; + + @override + String get mapCache_clearOfflineCachePrompt => 'Remove all cached map tiles?'; + + @override + String get mapCache_offlineCacheCleared => 'Offline cache cleared'; + + @override + String get mapCache_noAreaSelected => 'No area selected'; + + @override + String get mapCache_cacheArea => 'Cache Area'; + + @override + String get mapCache_useCurrentView => 'Use Current View'; + + @override + String get mapCache_zoomRange => 'Zoom Range'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Estimated tiles: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Downloaded $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Download Tiles'; + + @override + String get mapCache_clearCacheButton => 'Clear Cache'; + + @override + String mapCache_failedDownloads(int count) { + return 'Failed downloads: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Just now'; + + @override + String time_minutesAgo(int minutes) { + return '${minutes}m ago'; + } + + @override + String time_hoursAgo(int hours) { + return '${hours}h ago'; + } + + @override + String time_daysAgo(int days) { + return '${days}d ago'; + } + + @override + String get time_hour => 'hour'; + + @override + String get time_hours => 'hours'; + + @override + String get time_day => 'day'; + + @override + String get time_days => 'days'; + + @override + String get time_week => 'week'; + + @override + String get time_weeks => 'weeks'; + + @override + String get time_month => 'month'; + + @override + String get time_months => 'months'; + + @override + String get time_minutes => 'minutes'; + + @override + String get time_allTime => 'All Time'; + + @override + String get dialog_disconnect => 'Disconnect'; + + @override + String get dialog_disconnectConfirm => + 'Are you sure you want to disconnect from this device?'; + + @override + String get login_repeaterLogin => 'Repeater Login'; + + @override + String get login_roomLogin => 'Room Login'; + + @override + String get login_password => 'Password'; + + @override + String get login_enterPassword => 'Enter password'; + + @override + String get login_savePassword => 'Save password'; + + @override + String get login_savePasswordSubtitle => + 'Password will be stored securely on this device'; + + @override + String get login_repeaterDescription => + 'Enter the repeater password to access settings and status.'; + + @override + String get login_roomDescription => + 'Enter the room password to access settings and status.'; + + @override + String get login_routing => 'Routing'; + + @override + String get login_routingMode => 'Routing mode'; + + @override + String get login_autoUseSavedPath => 'Auto (use saved path)'; + + @override + String get login_forceFloodMode => 'Force Flood Mode'; + + @override + String get login_managePaths => 'Manage Paths'; + + @override + String get login_login => 'Login'; + + @override + String login_attempt(int current, int max) { + return 'Attempt $current/$max'; + } + + @override + String login_failed(String error) { + return 'Login failed: $error'; + } + + @override + String get common_reload => 'Reload'; + + @override + String get common_clear => 'Clear'; + + @override + String path_currentPath(String path) { + return 'Current path: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Using $count $_temp0 path'; + } + + @override + String get path_enterCustomPath => 'Enter Custom Path'; + + @override + String get path_currentPathLabel => 'Current path'; + + @override + String get path_hexPrefixInstructions => + 'Enter 2-character hex prefixes for each hop, separated by commas.'; + + @override + String get path_hexPrefixExample => + 'Example: A1,F2,3C (each node uses first byte of its public key)'; + + @override + String get path_labelHexPrefixes => 'Path (hex prefixes)'; + + @override + String get path_helperMaxHops => + 'Max 64 hops. Each prefix is 2 hex characters (1 byte)'; + + @override + String get path_selectFromContacts => 'Or select from contacts:'; + + @override + String get path_noRepeatersFound => 'No repeaters or room servers found.'; + + @override + String get path_customPathsRequire => + 'Custom paths require intermediate hops that can relay messages.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Invalid hex prefixes: $prefixes'; + } + + @override + String get path_tooLong => 'Path too long. Maximum 64 hops allowed.'; + + @override + String get path_setPath => 'Set Path'; + + @override + String get repeater_management => 'Repeater Management'; + + @override + String get repeater_managementTools => 'Management Tools'; + + @override + String get repeater_status => 'Status'; + + @override + String get repeater_statusSubtitle => + 'View repeater status, stats, and neighbors'; + + @override + String get repeater_telemetry => 'Telemetry'; + + @override + String get repeater_telemetrySubtitle => + 'View telemetry of sensors and system stats'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Send commands to the repeater'; + + @override + String get repeater_settings => 'Settings'; + + @override + String get repeater_settingsSubtitle => 'Configure repeater parameters'; + + @override + String get repeater_statusTitle => 'Repeater Status'; + + @override + String get repeater_routingMode => 'Routing mode'; + + @override + String get repeater_autoUseSavedPath => 'Auto (use saved path)'; + + @override + String get repeater_forceFloodMode => 'Force Flood Mode'; + + @override + String get repeater_pathManagement => 'Path management'; + + @override + String get repeater_refresh => 'Refresh'; + + @override + String get repeater_statusRequestTimeout => 'Status request timed out.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Error loading status: $error'; + } + + @override + String get repeater_systemInformation => 'System Information'; + + @override + String get repeater_battery => 'Battery'; + + @override + String get repeater_clockAtLogin => 'Clock (at login)'; + + @override + String get repeater_uptime => 'Uptime'; + + @override + String get repeater_queueLength => 'Queue Length'; + + @override + String get repeater_debugFlags => 'Debug Flags'; + + @override + String get repeater_radioStatistics => 'Radio Statistics'; + + @override + String get repeater_lastRssi => 'Last RSSI'; + + @override + String get repeater_lastSnr => 'Last SNR'; + + @override + String get repeater_noiseFloor => 'Noise Floor'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Packet Statistics'; + + @override + String get repeater_sent => 'Sent'; + + @override + String get repeater_received => 'Received'; + + @override + String get repeater_duplicates => 'Duplicates'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days days ${hours}h ${minutes}m ${seconds}s'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Total: $total, Flood: $flood, Direct: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Total: $total, Flood: $flood, Direct: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Flood: $flood, Direct: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Total: $total'; + } + + @override + String get repeater_settingsTitle => 'Repeater Settings'; + + @override + String get repeater_basicSettings => 'Basic Settings'; + + @override + String get repeater_repeaterName => 'Repeater Name'; + + @override + String get repeater_repeaterNameHelper => 'Display name for this repeater'; + + @override + String get repeater_adminPassword => 'Admin Password'; + + @override + String get repeater_adminPasswordHelper => 'Full access password'; + + @override + String get repeater_guestPassword => 'Guest Password'; + + @override + String get repeater_guestPasswordHelper => 'Read-only access password'; + + @override + String get repeater_radioSettings => 'Radio Settings'; + + @override + String get repeater_frequencyMhz => 'Frequency (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Power'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Bandwidth'; + + @override + String get repeater_spreadingFactor => 'Spreading Factor'; + + @override + String get repeater_codingRate => 'Coding Rate'; + + @override + String get repeater_locationSettings => 'Location Settings'; + + @override + String get repeater_latitude => 'Latitude'; + + @override + String get repeater_latitudeHelper => 'Decimal degrees (e.g., 37.7749)'; + + @override + String get repeater_longitude => 'Longitude'; + + @override + String get repeater_longitudeHelper => 'Decimal degrees (e.g., -122.4194)'; + + @override + String get repeater_features => 'Features'; + + @override + String get repeater_packetForwarding => 'Packet Forwarding'; + + @override + String get repeater_packetForwardingSubtitle => + 'Enable repeater to forward packets'; + + @override + String get repeater_guestAccess => 'Guest Access'; + + @override + String get repeater_guestAccessSubtitle => 'Allow read-only guest access'; + + @override + String get repeater_privacyMode => 'Privacy Mode'; + + @override + String get repeater_privacyModeSubtitle => + 'Hide name/location in advertisements'; + + @override + String get repeater_advertisementSettings => 'Advertisement Settings'; + + @override + String get repeater_localAdvertInterval => 'Local Advertisement Interval'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes minutes'; + } + + @override + String get repeater_floodAdvertInterval => 'Flood Advertisement Interval'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours hours'; + } + + @override + String get repeater_encryptedAdvertInterval => + 'Encrypted Advertisement Interval'; + + @override + String get repeater_dangerZone => 'Danger Zone'; + + @override + String get repeater_rebootRepeater => 'Reboot Repeater'; + + @override + String get repeater_rebootRepeaterSubtitle => 'Restart the repeater device'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Are you sure you want to reboot this repeater?'; + + @override + String get repeater_regenerateIdentityKey => 'Regenerate Identity Key'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Generate new public/private key pair'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'This will generate a new identity for the repeater. Continue?'; + + @override + String get repeater_eraseFileSystem => 'Erase File System'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Format the repeater file system'; + + @override + String get repeater_eraseFileSystemConfirm => + 'WARNING: This will erase all data on the repeater. This cannot be undone!'; + + @override + String get repeater_eraseSerialOnly => + 'Erase is only available over serial console.'; + + @override + String repeater_commandSent(String command) { + return 'Command sent: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Error sending command: $error'; + } + + @override + String get repeater_confirm => 'Confirm'; + + @override + String get repeater_settingsSaved => 'Settings saved successfully'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Error saving settings: $error'; + } + + @override + String get repeater_refreshBasicSettings => 'Refresh Basic Settings'; + + @override + String get repeater_refreshRadioSettings => 'Refresh Radio Settings'; + + @override + String get repeater_refreshTxPower => 'Refresh TX power'; + + @override + String get repeater_refreshLocationSettings => 'Refresh Location Settings'; + + @override + String get repeater_refreshPacketForwarding => 'Refresh Packet Forwarding'; + + @override + String get repeater_refreshGuestAccess => 'Refresh Guest Access'; + + @override + String get repeater_refreshPrivacyMode => 'Refresh Privacy Mode'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Refresh Advertisement Settings'; + + @override + String repeater_refreshed(String label) { + return '$label refreshed'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Error refreshing $label'; + } + + @override + String get repeater_cliTitle => 'Repeater CLI'; + + @override + String get repeater_debugNextCommand => 'Debug Next Command'; + + @override + String get repeater_commandHelp => 'Command Help'; + + @override + String get repeater_clearHistory => 'Clear History'; + + @override + String get repeater_noCommandsSent => 'No commands sent yet'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Type a command below or use quick commands'; + + @override + String get repeater_enterCommandHint => 'Enter command...'; + + @override + String get repeater_previousCommand => 'Previous command'; + + @override + String get repeater_nextCommand => 'Next command'; + + @override + String get repeater_enterCommandFirst => 'Enter a command first'; + + @override + String get repeater_cliCommandFrameTitle => 'CLI Command Frame'; + + @override + String repeater_cliCommandError(String error) { + return 'Error: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Get Name'; + + @override + String get repeater_cliQuickGetRadio => 'Get Radio'; + + @override + String get repeater_cliQuickGetTx => 'Get TX'; + + @override + String get repeater_cliQuickNeighbors => 'Neighbors'; + + @override + String get repeater_cliQuickVersion => 'Version'; + + @override + String get repeater_cliQuickAdvertise => 'Advertise'; + + @override + String get repeater_cliQuickClock => 'Clock'; + + @override + String get repeater_cliHelpAdvert => 'Sends an advertisement packet'; + + @override + String get repeater_cliHelpReboot => + 'Reboots the device. (note, you\'ll prob get \'Timeout\' which is normal)'; + + @override + String get repeater_cliHelpClock => + 'Displays current time per device\'s clock.'; + + @override + String get repeater_cliHelpPassword => + 'Sets a new admin password for the device.'; + + @override + String get repeater_cliHelpVersion => + 'Shows the device version and firmware build date.'; + + @override + String get repeater_cliHelpClearStats => + 'Resets various stats counters to zero.'; + + @override + String get repeater_cliHelpSetAf => 'Sets the air-time-factor.'; + + @override + String get repeater_cliHelpSetTx => + 'Sets LoRa transmit power in dBm. (reboot to apply)'; + + @override + String get repeater_cliHelpSetRepeat => + 'Enables or disables the repeater role for this node.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Room server) If \'on\', then login in blank password will be allowed, but cannot Post to room. (just read only)'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Sets the maximum number of hops of inbound flood packet (if >= max, packet is not forwarded)'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Sets the Interference Threshold (in DB). Default is 14. Set to 0 to disable channel interference detection.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Sets the interval to reset the Auto Gain Controller. Set to 0 to disable.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Enables or disables the \'double ACKs\' feature.'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Sets the timer interval in minutes to send a local (zero-hop) advertisement packet. Set to 0 to disable.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Sets the timer interval in hours to send a flood advertisement packet. Set to 0 to disable.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Sets/updates the guest password. (for repeaters, guest logins can send the \"Get Stats\" request)'; + + @override + String get repeater_cliHelpSetName => 'Sets the advertisement name.'; + + @override + String get repeater_cliHelpSetLat => + 'Sets the advertisement map latitude. (decimal degrees)'; + + @override + String get repeater_cliHelpSetLon => + 'Sets the advertisement map longitude. (decimal degrees)'; + + @override + String get repeater_cliHelpSetRadio => + 'Sets completely new radio params, and saves to preferences. Requires a \"reboot\" command to apply.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Sets (experimental) base (must be > 1 for effect) for applying slight delay to received packets, based on signal strength/score. Set to 0 to disable.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Sets a factor multiplied with time-on-air for a flood-mode packet and with a randomized slot system, to delay its forwarding. (to decrease likelihood of collisions)'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Same as txdelay, but for applying a random delay to the forwarding of direct-mode packets.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => 'Enable/Disable bridge.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Set delay before retransmitting packets.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Choose wether the bridge will retransmit received packets or transmitted packets.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Set serial link baudrate for rs232 bridges.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Set bridge secret for espnow bridges.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Sets custom factor to adjust reported battery voltage (only supported on select boards).'; + + @override + String get repeater_cliHelpTempRadio => + 'Sets temporary radio params for the given number of minutes, reverting to original radio params afterward. (does NOT save to preferences).'; + + @override + String get repeater_cliHelpSetPerm => + 'Modifies the ACL. Removes matching entry (by pubkey prefix) if \"permissions\" is zero. Adds new entry if pubkey-hex is full length and is not currently in ACL. Updates entry by matching pubkey prefix. Permission bits vary per firmware role, but low 2 bits are: 0 (Guest), 1 (Read only), 2 (Read write), 3 (Admin)'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Gets bridge type none, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => + 'Starts packet logging to file system.'; + + @override + String get repeater_cliHelpLogStop => 'Stops packet logging to file system.'; + + @override + String get repeater_cliHelpLogErase => + 'Erases the packet logs from file system.'; + + @override + String get repeater_cliHelpNeighbors => + 'Shows a list of other repeater nodes heard via zero-hop adverts. Each line is id-prefix-hex:timestamp:snr-times-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Removes first matching entry (by pubkey prefix (hex)), from neighbors list.'; + + @override + String get repeater_cliHelpRegion => + '(serial only) Lists all defined regions and current flood permissions.'; + + @override + String get repeater_cliHelpRegionLoad => + 'NOTE: this is a special multi-command invocation. Each subsequent command is a region name (indented with spaces to indicate parent hierarchy, with one space at minimum). Terminated by sending a blank line/command.'; + + @override + String get repeater_cliHelpRegionGet => + 'Searches for region with given name prefix (or \"*\" for the global scope). Replies with \"-> region-name (parent-name) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Adds or updates a region definition with given name.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Removes a region definition with given name. (must match exactly, and have no child regions)'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Sets the \'F\'lood permission for the given region. (\'*\' for the global/legacy scope)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Removes the \'F\'lood permission for the given region. (NOTE: at this stage NOT advised to use this on the global/legacy scope!!)'; + + @override + String get repeater_cliHelpRegionHome => + 'Replies with the current \'home\' region. (Note applied anywhere yet, reserved for future)'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Sets the \'home\' region.'; + + @override + String get repeater_cliHelpRegionSave => + 'Persists the region list/map to storage.'; + + @override + String get repeater_cliHelpGps => + 'Gives status of gps. When gps is off, it replies only off, if on it replies with on, status, fix, sat count'; + + @override + String get repeater_cliHelpGpsOnOff => 'Toggles gps power state.'; + + @override + String get repeater_cliHelpGpsSync => 'Syncs node time with gps clock.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Sets node\'s position to gps coordinates and save preferences.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Gives location advert configuration of the node:\n- none: don\'t include location in adverts\n- share: share gps location (from SensorManager)\n- prefs: advert the location stored in preferences'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Sets location advert configuration.'; + + @override + String get repeater_commandsListTitle => 'Commands List'; + + @override + String get repeater_commandsListNote => + 'NOTE: for the various \"set ...\" commands, there is also a \"get ...\" command.'; + + @override + String get repeater_general => 'General'; + + @override + String get repeater_settingsCategory => 'Settings'; + + @override + String get repeater_bridge => 'Bridge'; + + @override + String get repeater_logging => 'Logging'; + + @override + String get repeater_neighborsRepeaterOnly => 'Neighbors (Repeater only)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Region Management (Repeater only)'; + + @override + String get repeater_regionNote => + 'Region commands have been introduced to manage region definitions and permissions.'; + + @override + String get repeater_gpsManagement => 'GPS Management'; + + @override + String get repeater_gpsNote => + 'gps command has been introduced to manage location related topics.'; + + @override + String get telemetry_receivedData => 'Received Telemetry Data'; + + @override + String get telemetry_requestTimeout => 'Telemetry request timed out.'; + + @override + String telemetry_errorLoading(String error) { + return 'Error loading telemetry: $error'; + } + + @override + String get telemetry_noData => 'No telemetry data available.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Channel $channel'; + } + + @override + String get telemetry_batteryLabel => 'Battery'; + + @override + String get telemetry_voltageLabel => 'Voltage'; + + @override + String get telemetry_mcuTemperatureLabel => 'MCU Temperature'; + + @override + String get telemetry_temperatureLabel => 'Temperature'; + + @override + String get telemetry_currentLabel => 'Current'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Packet Path'; + + @override + String get channelPath_viewMap => 'View map'; + + @override + String get channelPath_otherObservedPaths => 'Other Observed Paths'; + + @override + String get channelPath_repeaterHops => 'Repeater Hops'; + + @override + String get channelPath_noHopDetails => + 'Hop details are not provided for this packet.'; + + @override + String get channelPath_messageDetails => 'Message Details'; + + @override + String get channelPath_senderLabel => 'Sender'; + + @override + String get channelPath_timeLabel => 'Time'; + + @override + String get channelPath_repeatsLabel => 'Repeats'; + + @override + String channelPath_pathLabel(int index) { + return 'Path $index'; + } + + @override + String get channelPath_observedLabel => 'Observed'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Observed path $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'No location data'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Unknown'; + + @override + String get channelPath_floodPath => 'Flood'; + + @override + String get channelPath_directPath => 'Direct'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 of $total hops'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed of $total hops'; + } + + @override + String get channelPath_mapTitle => 'Path Map'; + + @override + String get channelPath_noRepeaterLocations => + 'No repeater locations available for this path.'; + + @override + String channelPath_primaryPath(int index) { + return 'Path $index (Primary)'; + } + + @override + String get channelPath_pathLabelTitle => 'Path'; + + @override + String get channelPath_observedPathHeader => 'Observed Path'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'No hop details available for this packet.'; + + @override + String get channelPath_unknownRepeater => 'Unknown Repeater'; + + @override + String get listFilter_tooltip => 'Filter and sort'; + + @override + String get listFilter_sortBy => 'Sort by'; + + @override + String get listFilter_latestMessages => 'Latest messages'; + + @override + String get listFilter_heardRecently => 'Heard recently'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Filters'; + + @override + String get listFilter_all => 'All'; + + @override + String get listFilter_users => 'Users'; + + @override + String get listFilter_repeaters => 'Repeaters'; + + @override + String get listFilter_roomServers => 'Room servers'; + + @override + String get listFilter_unreadOnly => 'Unread only'; + + @override + String get listFilter_newGroup => 'New group'; +} diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart new file mode 100644 index 0000000..82259cf --- /dev/null +++ b/lib/l10n/app_localizations_es.dart @@ -0,0 +1,2389 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Spanish Castilian (`es`). +class AppLocalizationsEs extends AppLocalizations { + AppLocalizationsEs([String locale = 'es']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Contactos'; + + @override + String get nav_channels => 'Canales'; + + @override + String get nav_map => 'Mapa'; + + @override + String get common_cancel => 'Cancelar'; + + @override + String get common_connect => 'Conectar'; + + @override + String get common_unknownDevice => 'Dispositivo Desconocido'; + + @override + String get common_save => 'Guardar'; + + @override + String get common_delete => 'Eliminar'; + + @override + String get common_close => 'Cerrar'; + + @override + String get common_edit => 'Editar'; + + @override + String get common_add => 'Añadir'; + + @override + String get common_settings => 'Configuración'; + + @override + String get common_disconnect => 'Desconectar'; + + @override + String get common_connected => 'Conectado'; + + @override + String get common_disconnected => 'Desconectado'; + + @override + String get common_create => 'Crear'; + + @override + String get common_continue => 'Continuar'; + + @override + String get common_share => 'Compartir'; + + @override + String get common_copy => 'Copiar'; + + @override + String get common_retry => 'Intentar'; + + @override + String get common_hide => 'Ocultar'; + + @override + String get common_remove => 'Eliminar'; + + @override + String get common_enable => 'Activar'; + + @override + String get common_disable => 'Desactivar'; + + @override + String get common_reboot => 'Reiniciar'; + + @override + String get common_loading => 'Cargando...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Escaneando dispositivos...'; + + @override + String get scanner_connecting => 'Conectando...'; + + @override + String get scanner_disconnecting => 'Desconectando...'; + + @override + String get scanner_notConnected => 'No está conectado'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Conectado a $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Buscando dispositivos MeshCore...'; + + @override + String get scanner_tapToScan => + 'Toca Escanear para encontrar dispositivos MeshCore'; + + @override + String scanner_connectionFailed(String error) { + return 'Error de conexión: $error'; + } + + @override + String get scanner_stop => 'Detener'; + + @override + String get scanner_scan => 'Escanea'; + + @override + String get device_quickSwitch => 'Cambiar rápidamente'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Configuración'; + + @override + String get settings_deviceInfo => 'Información del dispositivo'; + + @override + String get settings_appSettings => 'Configuración de la App'; + + @override + String get settings_appSettingsSubtitle => + 'Notificaciones, mensajes y preferencias de mapa'; + + @override + String get settings_nodeSettings => 'Configuración del Nodo'; + + @override + String get settings_nodeName => 'Nombre del nodo'; + + @override + String get settings_nodeNameNotSet => 'No está configurado'; + + @override + String get settings_nodeNameHint => 'Introducir nombre de nodo'; + + @override + String get settings_nodeNameUpdated => 'Nombre actualizado'; + + @override + String get settings_radioSettings => 'Configuración de Radio'; + + @override + String get settings_radioSettingsSubtitle => + 'Frecuencia, potencia, factor de dispersión'; + + @override + String get settings_radioSettingsUpdated => 'Ajustes de radio actualizados'; + + @override + String get settings_location => 'Ubicación'; + + @override + String get settings_locationSubtitle => 'Coordenadas GPS'; + + @override + String get settings_locationUpdated => 'Ubicación actualizada'; + + @override + String get settings_locationBothRequired => + 'Introduzca tanto la latitud como la longitud.'; + + @override + String get settings_locationInvalid => 'Latitud o longitud inválidos.'; + + @override + String get settings_latitude => 'Latitud'; + + @override + String get settings_longitude => 'Longitud'; + + @override + String get settings_privacyMode => 'Modo Privacidad'; + + @override + String get settings_privacyModeSubtitle => + 'Ocultar nombre/ubicación en anuncios'; + + @override + String get settings_privacyModeToggle => + 'Activar el modo de privacidad para ocultar tu nombre y ubicación en los anuncios.'; + + @override + String get settings_privacyModeEnabled => 'Modo de privacidad activado'; + + @override + String get settings_privacyModeDisabled => 'Modo de privacidad desactivado'; + + @override + String get settings_actions => 'Acciones'; + + @override + String get settings_sendAdvertisement => 'Enviar Anuncio'; + + @override + String get settings_sendAdvertisementSubtitle => + 'Presencia de transmisión ahora'; + + @override + String get settings_advertisementSent => 'Anuncio enviado'; + + @override + String get settings_syncTime => 'Tiempo de Sincronización'; + + @override + String get settings_syncTimeSubtitle => + 'Establecer la hora del dispositivo al tiempo del teléfono'; + + @override + String get settings_timeSynchronized => 'Sincronizado en el tiempo'; + + @override + String get settings_refreshContacts => 'Actualizar Contactos'; + + @override + String get settings_refreshContactsSubtitle => + 'Recargar lista de contactos del dispositivo'; + + @override + String get settings_rebootDevice => 'Reiniciar Dispositivo'; + + @override + String get settings_rebootDeviceSubtitle => + 'Reiniciar el dispositivo MeshCore'; + + @override + String get settings_rebootDeviceConfirm => + '¿Está seguro de que desea reiniciar el dispositivo? Se desconectará.'; + + @override + String get settings_debug => 'Depurar'; + + @override + String get settings_bleDebugLog => 'Registro de Depuración BLE'; + + @override + String get settings_bleDebugLogSubtitle => + 'Comandos, respuestas y datos brutos de BLE'; + + @override + String get settings_appDebugLog => 'Registro de Depuración de la App'; + + @override + String get settings_appDebugLogSubtitle => + 'Mensajes de depuración de la aplicación'; + + @override + String get settings_about => 'Acerca de'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => '2026 Proyecto Open Source MeshCore'; + + @override + String get settings_aboutDescription => + 'Un cliente de código abierto de Flutter para dispositivos de red mesh LoRa de MeshCore.'; + + @override + String get settings_infoName => 'Nombre'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'Estado'; + + @override + String get settings_infoBattery => 'Batería'; + + @override + String get settings_infoPublicKey => 'Clave Pública'; + + @override + String get settings_infoContactsCount => 'Número de contactos'; + + @override + String get settings_infoChannelCount => 'Número de canales'; + + @override + String get settings_presets => 'Preajustes'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Frecuencia (MHz)'; + + @override + String get settings_frequencyHelper => '300,0 - 2500,0'; + + @override + String get settings_frequencyInvalid => 'Frecuencia inválida (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Ancho de banda'; + + @override + String get settings_spreadingFactor => 'Factor de propagación'; + + @override + String get settings_codingRate => 'Tasa de Programación'; + + @override + String get settings_txPower => 'TX Potencia (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Potencia de TX inválida (0-22 dBm)'; + + @override + String get settings_longRange => 'Largo Alcance'; + + @override + String get settings_fastSpeed => 'Velocidad Rápida'; + + @override + String settings_error(String message) { + return 'Error: $message'; + } + + @override + String get appSettings_title => 'Configuración de la App'; + + @override + String get appSettings_appearance => 'Apariencia'; + + @override + String get appSettings_theme => 'Tema'; + + @override + String get appSettings_themeSystem => 'Valor predeterminado del sistema'; + + @override + String get appSettings_themeLight => 'Luz'; + + @override + String get appSettings_themeDark => 'Oscuro'; + + @override + String get appSettings_language => 'Idioma'; + + @override + String get appSettings_languageSystem => 'Predeterminado del sistema'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Notificaciones'; + + @override + String get appSettings_enableNotifications => 'Habilitar Notificaciones'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Recibir notificaciones para mensajes y anuncios'; + + @override + String get appSettings_notificationPermissionDenied => + 'Permiso de notificación denegado'; + + @override + String get appSettings_notificationsEnabled => 'Notificaciones activadas'; + + @override + String get appSettings_notificationsDisabled => 'Notificaciones desactivadas'; + + @override + String get appSettings_messageNotifications => 'Notificaciones de Mensaje'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Mostrar notificación al recibir nuevos mensajes'; + + @override + String get appSettings_channelMessageNotifications => + 'Notificaciones de Mensajes del Canal'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Mostrar notificación al recibir mensajes del canal'; + + @override + String get appSettings_advertisementNotifications => + 'Notificaciones de Anuncios'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Mostrar notificación cuando se descubren nuevos nodos'; + + @override + String get appSettings_messaging => 'Mensajería'; + + @override + String get appSettings_clearPathOnMaxRetry => + 'Borrar Camino en Max Reintentos'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Restablecer la ruta de contacto después de 5 intentos de envío fallidos'; + + @override + String get appSettings_pathsWillBeCleared => + 'Los caminos se limpiarán después de 5 intentos fallidos.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Las rutas no se eliminarán automáticamente.'; + + @override + String get appSettings_autoRouteRotation => 'Rotación de Ruta Automática'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Alternar entre las mejores rutas y el modo inundación'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Rotación de ruta automática habilitada'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Rotación de ruta automática desactivada'; + + @override + String get appSettings_battery => 'Batería'; + + @override + String get appSettings_batteryChemistry => 'Química de la batería'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Configuración por dispositivo ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Conéctate a un dispositivo para elegir'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3.0-4.2V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2.6-3.65V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3.0-4.2V)'; + + @override + String get appSettings_mapDisplay => 'Visualización del Mapa'; + + @override + String get appSettings_showRepeaters => 'Mostrar Repetidores'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Mostrar nodos de repetidor en el mapa'; + + @override + String get appSettings_showChatNodes => 'Mostrar Nodos de Chat'; + + @override + String get appSettings_showChatNodesSubtitle => + 'Mostrar nodos de chat en el mapa'; + + @override + String get appSettings_showOtherNodes => 'Mostrar otros nodos'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Mostrar otros tipos de nodo en el mapa'; + + @override + String get appSettings_timeFilter => 'Filtro de Tiempo'; + + @override + String get appSettings_timeFilterShowAll => 'Mostrar todos los nodos'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Mostrar nodos de las últimas $hours horas'; + } + + @override + String get appSettings_mapTimeFilter => 'Filtro de Tiempo del Mapa'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Mostrar nodos descubiertos dentro de:'; + + @override + String get appSettings_allTime => 'Todo el tiempo'; + + @override + String get appSettings_lastHour => 'Última hora'; + + @override + String get appSettings_last6Hours => 'Últimas 6 horas'; + + @override + String get appSettings_last24Hours => 'Últimas 24 horas'; + + @override + String get appSettings_lastWeek => 'La semana pasada'; + + @override + String get appSettings_offlineMapCache => 'Caché de Mapa Offline'; + + @override + String get appSettings_noAreaSelected => 'No se ha seleccionado ningún área'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Área seleccionada (zoom $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Depurar'; + + @override + String get appSettings_appDebugLogging => 'Registro de Depuración de la App'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Registrar mensajes de depuración de la app de registro para solucionar problemas'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'Registro de depuración de la aplicación habilitado'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'El registro de depuración de la aplicación está desactivado'; + + @override + String get contacts_title => 'Contactos'; + + @override + String get contacts_noContacts => 'Aún no hay contactos.'; + + @override + String get contacts_contactsWillAppear => + 'Los contactos aparecerán cuando los dispositivos anuncien.'; + + @override + String get contacts_searchContacts => 'Buscar contactos...'; + + @override + String get contacts_noUnreadContacts => 'No contactos sin leer'; + + @override + String get contacts_noContactsFound => + 'No se encontraron contactos ni grupos.'; + + @override + String get contacts_deleteContact => 'Eliminar Contacto'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Eliminar $contactName de los contactos?'; + } + + @override + String get contacts_manageRepeater => 'Gestionar Repetidor'; + + @override + String get contacts_roomLogin => 'Inicio de Sala'; + + @override + String get contacts_openChat => 'Abrir Chat'; + + @override + String get contacts_editGroup => 'Editar Grupo'; + + @override + String get contacts_deleteGroup => 'Eliminar Grupo'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Eliminar $groupName?'; + } + + @override + String get contacts_newGroup => 'Nuevo Grupo'; + + @override + String get contacts_groupName => 'Nombre del grupo'; + + @override + String get contacts_groupNameRequired => 'El nombre del grupo es obligatorio'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'El grupo \"$name\" ya existe'; + } + + @override + String get contacts_filterContacts => 'Filtrar contactos...'; + + @override + String get contacts_noContactsMatchFilter => + 'No hay contactos que coincidan con tu filtro'; + + @override + String get contacts_noMembers => 'No miembros'; + + @override + String get contacts_lastSeenNow => 'Última vez que se vio ahora'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Última vez visto hace $minutes minutos.'; + } + + @override + String get contacts_lastSeenHourAgo => 'Última vez que se vio hace 1 hora'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Última vez visto hace $hours horas.'; + } + + @override + String get contacts_lastSeenDayAgo => 'Última vez que se vio hace 1 día'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Última vez visto hace $days días.'; + } + + @override + String get channels_title => 'Canales'; + + @override + String get channels_noChannelsConfigured => 'No se han configurado canales'; + + @override + String get channels_addPublicChannel => 'Añadir Canal Público'; + + @override + String get channels_searchChannels => 'Buscar canales...'; + + @override + String get channels_noChannelsFound => 'No se encontraron canales'; + + @override + String channels_channelIndex(int index) { + return 'Canal $index'; + } + + @override + String get channels_hashtagChannel => 'Canal con hashtag'; + + @override + String get channels_public => 'Público'; + + @override + String get channels_private => 'Privado'; + + @override + String get channels_publicChannel => 'Canal público'; + + @override + String get channels_privateChannel => 'Canal privado'; + + @override + String get channels_editChannel => 'Editar canal'; + + @override + String get channels_deleteChannel => 'Eliminar canal'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Eliminar \"$name\"? Esto no se puede deshacer.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Canal \"$name\" eliminado'; + } + + @override + String get channels_addChannel => 'Añadir Canal'; + + @override + String get channels_channelIndexLabel => 'Índice de Canal'; + + @override + String get channels_channelName => 'Nombre del canal'; + + @override + String get channels_usePublicChannel => 'Usar Canal Público'; + + @override + String get channels_standardPublicPsk => 'PSK estándar público'; + + @override + String get channels_pskHex => 'PSK (Hex)'; + + @override + String get channels_generateRandomPsk => 'Generar PSK aleatorio'; + + @override + String get channels_enterChannelName => + 'Por favor, introduce un nombre de canal'; + + @override + String get channels_pskMustBe32Hex => + 'PSK debe ser de 32 caracteres hexadecimales.'; + + @override + String channels_channelAdded(String name) { + return 'Canal \"$name\" añadido'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Editar Canal $index'; + } + + @override + String get channels_smazCompression => 'Compresión SMAZ'; + + @override + String channels_channelUpdated(String name) { + return 'Canal \"$name\" actualizado'; + } + + @override + String get channels_publicChannelAdded => 'Canal público añadido'; + + @override + String get channels_sortBy => 'Ordenar por'; + + @override + String get channels_sortManual => 'Manual'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => 'Últimos mensajes'; + + @override + String get channels_sortUnread => 'Sin leer'; + + @override + String get chat_noMessages => 'Aún no hay mensajes'; + + @override + String get chat_sendMessageToStart => 'Enviar un mensaje para comenzar'; + + @override + String get chat_originalMessageNotFound => 'Mensaje original no encontrado'; + + @override + String chat_replyingTo(String name) { + return 'Responder a $name'; + } + + @override + String chat_replyTo(String name) { + return 'Responder a $name'; + } + + @override + String get chat_location => 'Ubicación'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Enviar un mensaje a $contactName'; + } + + @override + String get chat_typeMessage => 'Escribe un mensaje...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Mensaje demasiado largo (máximo $maxBytes bytes).'; + } + + @override + String get chat_messageCopied => 'Mensaje copiado'; + + @override + String get chat_messageDeleted => 'Mensaje borrado'; + + @override + String get chat_retryingMessage => 'Reintentando…'; + + @override + String chat_retryCount(int current, int max) { + return 'Reintentar $current/$max'; + } + + @override + String get chat_sendGif => 'Enviar GIF'; + + @override + String get chat_reply => 'Responder'; + + @override + String get chat_addReaction => 'Añadir Reacción'; + + @override + String get chat_me => 'Yo'; + + @override + String get emojiCategorySmileys => 'Emoticones'; + + @override + String get emojiCategoryGestures => 'Gestos'; + + @override + String get emojiCategoryHearts => 'Corazones'; + + @override + String get emojiCategoryObjects => 'Objetos'; + + @override + String get gifPicker_title => 'Elegir un GIF'; + + @override + String get gifPicker_searchHint => 'Buscar GIFs...'; + + @override + String get gifPicker_poweredBy => 'Powered by GIPHY'; + + @override + String get gifPicker_noGifsFound => 'No se encontraron GIFs'; + + @override + String get gifPicker_failedLoad => 'No se pudo cargar los GIFs'; + + @override + String get gifPicker_failedSearch => 'No se encontraron GIFs'; + + @override + String get gifPicker_noInternet => 'No hay conexión a internet'; + + @override + String get debugLog_appTitle => 'Registro de Depuración de la App'; + + @override + String get debugLog_bleTitle => 'Registro de Depuración BLE'; + + @override + String get debugLog_copyLog => 'Copiar registro'; + + @override + String get debugLog_clearLog => 'Borrar registro'; + + @override + String get debugLog_copied => 'Registro de depuración copiado'; + + @override + String get debugLog_bleCopied => 'Registro BLE copiado'; + + @override + String get debugLog_noEntries => 'Aún no hay registros de depuración.'; + + @override + String get debugLog_enableInSettings => + 'Habilitar el registro de depuración de la aplicación en la configuración'; + + @override + String get debugLog_frames => 'Marcos'; + + @override + String get debugLog_rawLogRx => 'Registro Crudo-RX'; + + @override + String get debugLog_noBleActivity => 'Aún no hay actividad BLE'; + + @override + String debugFrame_length(int count) { + return 'Longitud del Marco: $count bytes'; + } + + @override + String debugFrame_command(String value) { + return 'Comando: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Mensaje de Texto:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Destino PubKey: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Marca de tiempo: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Banderas: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Tipo de texto: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Sencillo'; + + @override + String debugFrame_text(String text) { + return '- Texto: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Mapeo Hexadecimal:'; + + @override + String get chat_pathManagement => 'Gestión de Rutas'; + + @override + String get chat_routingMode => 'Modo de enrutamiento'; + + @override + String get chat_autoUseSavedPath => 'Auto (usar la ruta guardada)'; + + @override + String get chat_forceFloodMode => 'Modo Inundación Forzado'; + + @override + String get chat_recentAckPaths => 'Rutas de ACK Recientes (tocar para usar):'; + + @override + String get chat_pathHistoryFull => + 'El historial de rutas está completo. Eliminar entradas para añadir nuevas.'; + + @override + String get chat_hopSingular => 'salta'; + + @override + String get chat_hopPlural => 'salta'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'Éxitos'; + + @override + String get chat_removePath => 'Eliminar ruta'; + + @override + String get chat_noPathHistoryYet => + 'Aún no hay historial de rutas.\nEnvía un mensaje para descubrir rutas.'; + + @override + String get chat_pathActions => 'Acciones de Ruta:'; + + @override + String get chat_setCustomPath => 'Establecer Ruta Personalizada'; + + @override + String get chat_setCustomPathSubtitle => + 'Especificar manualmente la ruta de enrutamiento'; + + @override + String get chat_clearPath => 'Limpiar Ruta'; + + @override + String get chat_clearPathSubtitle => + 'Forzar redescubrimiento en el próximo envío'; + + @override + String get chat_pathCleared => + 'Ruta eliminada. El siguiente mensaje redescubrirá la ruta.'; + + @override + String get chat_floodModeSubtitle => + 'Utilizar el interruptor de enrutamiento en la barra de herramientas'; + + @override + String get chat_floodModeEnabled => + 'El modo de inundación está habilitado. Desactívalo mediante el icono de enrutamiento en la barra de herramientas de la aplicación.'; + + @override + String get chat_fullPath => 'Ruta completa'; + + @override + String get chat_pathDetailsNotAvailable => + 'Los detalles de la ruta aún no están disponibles. Intenta enviar un mensaje para refrescar.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Ruta establecida: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Guardado localmente. Conéctate para sincronizar.'; + + @override + String get chat_pathDeviceConfirmed => 'Dispositivo confirmado.'; + + @override + String get chat_pathDeviceNotConfirmed => 'Dispositivo aún no confirmado.'; + + @override + String get chat_type => 'Escribe'; + + @override + String get chat_path => 'Ruta'; + + @override + String get chat_publicKey => 'Clave Pública'; + + @override + String get chat_compressOutgoingMessages => 'Comprimir mensajes salientes'; + + @override + String get chat_floodForced => 'Inundación (forzada)'; + + @override + String get chat_directForced => 'Directo (forzado)'; + + @override + String chat_hopsForced(int count) { + return '$count saltos (forzados)'; + } + + @override + String get chat_floodAuto => 'Inundación (automática)'; + + @override + String get chat_direct => 'Guardar'; + + @override + String get chat_poiShared => 'Punto de Interés Compartido'; + + @override + String chat_unread(int count) { + return 'Sin leer: $count'; + } + + @override + String get map_title => 'Mapa de Nodos'; + + @override + String get map_noNodesWithLocation => 'No hay nodos con datos de ubicación'; + + @override + String get map_nodesNeedGps => + 'Los nodos necesitan compartir sus coordenadas GPS\npara aparecer en el mapa'; + + @override + String map_nodesCount(int count) { + return 'Nodos: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Ganchos: $count'; + } + + @override + String get map_chat => 'Chat'; + + @override + String get map_repeater => 'Repetidor'; + + @override + String get map_room => 'Habitación'; + + @override + String get map_sensor => 'Sensor'; + + @override + String get map_pinDm => 'Pin (DM)'; + + @override + String get map_pinPrivate => 'Bloqueo (Privado)'; + + @override + String get map_pinPublic => 'Clave (Pública)'; + + @override + String get map_lastSeen => 'Última vez que se vio'; + + @override + String get map_disconnectConfirm => + '¿Está seguro de que desea desconectarse de este dispositivo?'; + + @override + String get map_from => 'De'; + + @override + String get map_source => 'Fuente'; + + @override + String get map_flags => 'Banderas'; + + @override + String get map_shareMarkerHere => 'Compartir marcador aquí'; + + @override + String get map_pinLabel => 'Etiqueta de marcador'; + + @override + String get map_label => 'Etiqueta'; + + @override + String get map_pointOfInterest => 'Punto de interés'; + + @override + String get map_sendToContact => 'Enviar a contacto'; + + @override + String get map_sendToChannel => 'Enviar a canal'; + + @override + String get map_noChannelsAvailable => 'No hay canales disponibles'; + + @override + String get map_publicLocationShare => 'Compartir ubicación pública'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'Estás a punto de compartir una ubicación en $channelLabel. Este canal es público y cualquiera con la PSK puede verlo.'; + } + + @override + String get map_connectToShareMarkers => + 'Conéctate a un dispositivo para compartir marcadores'; + + @override + String get map_filterNodes => 'Filtrar Nodos'; + + @override + String get map_nodeTypes => 'Tipos de nodo'; + + @override + String get map_chatNodes => 'Nodos de Chat'; + + @override + String get map_repeaters => 'Repetidores'; + + @override + String get map_otherNodes => 'Otros Nodos'; + + @override + String get map_keyPrefix => 'Prefijo de clave'; + + @override + String get map_filterByKeyPrefix => 'Filtrar por prefijo clave'; + + @override + String get map_publicKeyPrefix => 'Prefijo de clave pública'; + + @override + String get map_markers => 'Marcadores'; + + @override + String get map_showSharedMarkers => 'Mostrar marcadores compartidos'; + + @override + String get map_lastSeenTime => 'Última vez que se vio'; + + @override + String get map_sharedPin => 'Pin compartido'; + + @override + String get map_joinRoom => 'Únete a la sala'; + + @override + String get map_manageRepeater => 'Gestionar Repetidor'; + + @override + String get mapCache_title => 'Caché de Mapa Offline'; + + @override + String get mapCache_selectAreaFirst => + 'Seleccionar un área para cachear primero'; + + @override + String get mapCache_noTilesToDownload => + 'No hay azulejos para descargar para este área.'; + + @override + String get mapCache_downloadTilesTitle => 'Descargar ficheros'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Descargar $count ficheros para usar sin conexión?'; + } + + @override + String get mapCache_downloadAction => 'Descargar'; + + @override + String mapCache_cachedTiles(int count) { + return 'Almacenados $count azulejos'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Archivados $downloaded azulejos ($failed fallidos)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => 'Borrar caché offline'; + + @override + String get mapCache_clearOfflineCachePrompt => + 'Eliminar todas las baldosas en caché del mapa?'; + + @override + String get mapCache_offlineCacheCleared => + 'Almacén en caché sin conexión eliminado'; + + @override + String get mapCache_noAreaSelected => 'No se ha seleccionado ningún área'; + + @override + String get mapCache_cacheArea => 'Área de Caché'; + + @override + String get mapCache_useCurrentView => 'Usar Vista Actual'; + + @override + String get mapCache_zoomRange => 'Rango de Zoom'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Tiles estimados: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Descargados $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Descargar Mosaicos'; + + @override + String get mapCache_clearCacheButton => 'Borrar Caché'; + + @override + String mapCache_failedDownloads(int count) { + return 'Descargas fallidas: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Hace un momento'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes minutos hace.'; + } + + @override + String time_hoursAgo(int hours) { + return '${hours}h hace'; + } + + @override + String time_daysAgo(int days) { + return '$days días hace'; + } + + @override + String get time_hour => 'hora'; + + @override + String get time_hours => 'horas'; + + @override + String get time_day => 'día'; + + @override + String get time_days => 'días'; + + @override + String get time_week => 'semana'; + + @override + String get time_weeks => 'semanas'; + + @override + String get time_month => 'mes'; + + @override + String get time_months => 'meses'; + + @override + String get time_minutes => 'minutos'; + + @override + String get time_allTime => 'Todas las veces'; + + @override + String get dialog_disconnect => 'Desconectar'; + + @override + String get dialog_disconnectConfirm => + '¿Está seguro de que desea desconectarse de este dispositivo?'; + + @override + String get login_repeaterLogin => 'Iniciar sesión en el Repetidor'; + + @override + String get login_roomLogin => 'Inicio de Sala'; + + @override + String get login_password => 'Contraseña'; + + @override + String get login_enterPassword => 'Introducir contraseña'; + + @override + String get login_savePassword => 'Guardar contraseña'; + + @override + String get login_savePasswordSubtitle => + 'La contraseña se almacenará de forma segura en este dispositivo.'; + + @override + String get login_repeaterDescription => + 'Ingrese la contraseña del repetidor para acceder a la configuración y el estado.'; + + @override + String get login_roomDescription => + 'Ingrese la contraseña de la sala para acceder a la configuración y el estado.'; + + @override + String get login_routing => 'Enrutamiento'; + + @override + String get login_routingMode => 'Modo de enrutamiento'; + + @override + String get login_autoUseSavedPath => 'Auto (usar la ruta guardada)'; + + @override + String get login_forceFloodMode => 'Activar Modo Inundación Forzada'; + + @override + String get login_managePaths => 'Gestionar Rutas'; + + @override + String get login_login => 'Iniciar sesión'; + + @override + String login_attempt(int current, int max) { + return 'Intentar $current/$max'; + } + + @override + String login_failed(String error) { + return 'Inicio fallido: $error'; + } + + @override + String get common_reload => 'Recargar'; + + @override + String get common_clear => 'Borrar'; + + @override + String path_currentPath(String path) { + return 'Ruta actual: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Usando $count $_temp0 ruta'; + } + + @override + String get path_enterCustomPath => 'Introducir Ruta Personalizada'; + + @override + String get path_currentPathLabel => 'Ruta actual'; + + @override + String get path_hexPrefixInstructions => + 'Introduzca los prefijos hexadecimales de 2 caracteres para cada salto, separados por comas.'; + + @override + String get path_hexPrefixExample => + 'Ejemplo: A1,F2,3C (cada nodo utiliza el primer byte de su clave pública).'; + + @override + String get path_labelHexPrefixes => 'Prefijos hexadecimales'; + + @override + String get path_helperMaxHops => + 'Máximo 64 saltos. Cada prefijo tiene 2 caracteres hexadecimales (1 byte).'; + + @override + String get path_selectFromContacts => 'O seleccionar de contactos:'; + + @override + String get path_noRepeatersFound => + 'No se encontraron repetidores ni servidores de sala.'; + + @override + String get path_customPathsRequire => + 'Las rutas personalizadas requieren saltos intermedios que pueden transmitir mensajes.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Prefijos hexadecimales inválidos: $prefixes'; + } + + @override + String get path_tooLong => + 'La ruta es demasiado larga. Se permiten un máximo de 64 saltos.'; + + @override + String get path_setPath => 'Establecer Ruta'; + + @override + String get repeater_management => 'Gestión de Repetidores'; + + @override + String get repeater_managementTools => 'Herramientas de Gestión'; + + @override + String get repeater_status => 'Estado'; + + @override + String get repeater_statusSubtitle => + 'Ver el estado, las estadísticas y los vecinos del repetidor'; + + @override + String get repeater_telemetry => 'Telemetry'; + + @override + String get repeater_telemetrySubtitle => + 'Ver la telemetría de los sensores y las estadísticas del sistema'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Enviar comandos al repetidor'; + + @override + String get repeater_settings => 'Configuración'; + + @override + String get repeater_settingsSubtitle => 'Configurar parámetros del repetidor'; + + @override + String get repeater_statusTitle => 'Estado del Repetidor'; + + @override + String get repeater_routingMode => 'Modo de enrutamiento'; + + @override + String get repeater_autoUseSavedPath => 'Auto (usar la ruta guardada)'; + + @override + String get repeater_forceFloodMode => 'Modo Inundación Forzado'; + + @override + String get repeater_pathManagement => 'Gestión de rutas'; + + @override + String get repeater_refresh => 'Actualizar'; + + @override + String get repeater_statusRequestTimeout => 'Solicitud de estado caducó.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Error al cargar el estado: $error'; + } + + @override + String get repeater_systemInformation => 'Información del sistema'; + + @override + String get repeater_battery => 'Batería'; + + @override + String get repeater_clockAtLogin => 'Reloj (al inicio de sesión)'; + + @override + String get repeater_uptime => 'Tiempo de actividad'; + + @override + String get repeater_queueLength => 'Longitud de la cola'; + + @override + String get repeater_debugFlags => 'Marcadores de Depuración'; + + @override + String get repeater_radioStatistics => 'Estadísticas de Radio'; + + @override + String get repeater_lastRssi => 'Último RSSI'; + + @override + String get repeater_lastSnr => 'Último SNR'; + + @override + String get repeater_noiseFloor => 'Nivel de Ruido'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Estadísticas del Paquete'; + + @override + String get repeater_sent => 'Enviado'; + + @override + String get repeater_received => 'Recibido'; + + @override + String get repeater_duplicates => 'Duplicados'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days días ${hours}h ${minutes}m ${seconds}s'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Total: $total, Inundación: $flood, Directo: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Total: $total, Inundación: $flood, Directo: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Inundación: $flood, Directo: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Total: $total'; + } + + @override + String get repeater_settingsTitle => 'Configuración del Repetidor'; + + @override + String get repeater_basicSettings => 'Configuración Básica'; + + @override + String get repeater_repeaterName => 'Nombre del Repetidor'; + + @override + String get repeater_repeaterNameHelper => + 'Mostrar nombre para este repetidor'; + + @override + String get repeater_adminPassword => 'Contraseña de Administrador'; + + @override + String get repeater_adminPasswordHelper => 'Contraseña de acceso completo'; + + @override + String get repeater_guestPassword => 'Contraseña de invitado'; + + @override + String get repeater_guestPasswordHelper => + 'Acceso de solo lectura con contraseña'; + + @override + String get repeater_radioSettings => 'Configuración de Radio'; + + @override + String get repeater_frequencyMhz => 'Frecuencia (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Potencia'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Ancho de banda'; + + @override + String get repeater_spreadingFactor => 'Factor de propagación'; + + @override + String get repeater_codingRate => 'Tasa de Programación'; + + @override + String get repeater_locationSettings => 'Configuración de Ubicación'; + + @override + String get repeater_latitude => 'Latitud'; + + @override + String get repeater_latitudeHelper => + 'Grados decimales (por ejemplo, 37.7749)'; + + @override + String get repeater_longitude => 'Longitud'; + + @override + String get repeater_longitudeHelper => + 'Grados decimales (por ejemplo, -122.4194)'; + + @override + String get repeater_features => 'Características'; + + @override + String get repeater_packetForwarding => 'Enrutamiento de Paquetes'; + + @override + String get repeater_packetForwardingSubtitle => + 'Habilitar el repetidor para reenviar paquetes'; + + @override + String get repeater_guestAccess => 'Acceso de Invitados'; + + @override + String get repeater_guestAccessSubtitle => + 'Permitir acceso de invitado en solo lectura'; + + @override + String get repeater_privacyMode => 'Modo Privacidad'; + + @override + String get repeater_privacyModeSubtitle => + 'Ocultar nombre/ubicación en anuncios'; + + @override + String get repeater_advertisementSettings => 'Configuración de Anuncios'; + + @override + String get repeater_localAdvertInterval => 'Intervalo de Anuncio Local'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes minutos'; + } + + @override + String get repeater_floodAdvertInterval => + 'Intervalo de Anuncio de Inundación'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours horas'; + } + + @override + String get repeater_encryptedAdvertInterval => 'Intervalo de Anuncio Cifrado'; + + @override + String get repeater_dangerZone => 'Zona de Peligro'; + + @override + String get repeater_rebootRepeater => 'Reiniciar Repetidor'; + + @override + String get repeater_rebootRepeaterSubtitle => + 'Reiniciar el dispositivo repetidor'; + + @override + String get repeater_rebootRepeaterConfirm => + '¿Está seguro de que desea reiniciar este repetidor?'; + + @override + String get repeater_regenerateIdentityKey => 'Regenerar Clave de Identidad'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Generar nueva pareja de clave pública/privada'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'Esto generará una nueva identidad para el repetidor. Continuar?'; + + @override + String get repeater_eraseFileSystem => 'Borrar Sistema de Archivos'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Formatear el sistema de archivos del repetidor'; + + @override + String get repeater_eraseFileSystemConfirm => + 'ADVERTENCIA: Esto borrará todos los datos del repetidor. ¡Esto no se puede deshacer!'; + + @override + String get repeater_eraseSerialOnly => + 'Borrar solo está disponible a través de la consola serial.'; + + @override + String repeater_commandSent(String command) { + return 'Comando enviado: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Error al enviar el comando: $error'; + } + + @override + String get repeater_confirm => 'Confirmar'; + + @override + String get repeater_settingsSaved => 'Guardado de ajustes exitoso'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Error al guardar la configuración: $error'; + } + + @override + String get repeater_refreshBasicSettings => 'Actualizar Configuración Básica'; + + @override + String get repeater_refreshRadioSettings => 'Actualizar Ajustes de Radio'; + + @override + String get repeater_refreshTxPower => 'Actualizar TX de energía'; + + @override + String get repeater_refreshLocationSettings => + 'Actualizar Configuración de Ubicación'; + + @override + String get repeater_refreshPacketForwarding => + 'Actualizar Enrutamiento de Paquetes'; + + @override + String get repeater_refreshGuestAccess => 'Actualizar Acceso Invitados'; + + @override + String get repeater_refreshPrivacyMode => 'Actualizar Modo Privacidad'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Actualizar Configuración de Anuncios'; + + @override + String repeater_refreshed(String label) { + return '$label actualizado'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Error al refrescar $label'; + } + + @override + String get repeater_cliTitle => 'Repetidor CLI'; + + @override + String get repeater_debugNextCommand => 'Siguiente Comando de Depuración'; + + @override + String get repeater_commandHelp => 'Ayuda'; + + @override + String get repeater_clearHistory => 'Borrar historial'; + + @override + String get repeater_noCommandsSent => 'Aún no se han enviado comandos.'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Escriba un comando a continuación o use comandos rápidos'; + + @override + String get repeater_enterCommandHint => 'Escribir comando...'; + + @override + String get repeater_previousCommand => 'Comando anterior'; + + @override + String get repeater_nextCommand => 'Siguiente comando'; + + @override + String get repeater_enterCommandFirst => 'Escriba un comando primero'; + + @override + String get repeater_cliCommandFrameTitle => 'Marco de Comando CLI'; + + @override + String repeater_cliCommandError(String error) { + return 'Error: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Obtener Nombre'; + + @override + String get repeater_cliQuickGetRadio => 'Obtener Radio'; + + @override + String get repeater_cliQuickGetTx => 'Obtener TX'; + + @override + String get repeater_cliQuickNeighbors => 'Vecinos'; + + @override + String get repeater_cliQuickVersion => 'Versión'; + + @override + String get repeater_cliQuickAdvertise => 'Anunciar'; + + @override + String get repeater_cliQuickClock => 'Reloj'; + + @override + String get repeater_cliHelpAdvert => 'Envía un paquete de publicidad'; + + @override + String get repeater_cliHelpReboot => + 'Reinicia el dispositivo. (ten en cuenta, es normal que aparezca \'Timeout\')'; + + @override + String get repeater_cliHelpClock => + 'Muestra la hora actual según el reloj del dispositivo.'; + + @override + String get repeater_cliHelpPassword => + 'Establece una nueva contraseña de administrador para el dispositivo.'; + + @override + String get repeater_cliHelpVersion => + 'Muestra la versión del dispositivo y la fecha de compilación del firmware.'; + + @override + String get repeater_cliHelpClearStats => + 'Reinicia varios contadores de estadísticas a cero.'; + + @override + String get repeater_cliHelpSetAf => 'Establece el factor de tiempo de aire.'; + + @override + String get repeater_cliHelpSetTx => + 'Establece la potencia de transmisión LoRa en dBm (reboot para aplicar).'; + + @override + String get repeater_cliHelpSetRepeat => + 'Habilita o deshabilita el rol del repetidor para este nodo.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Servidor de la sala) Si está \"activado\", entonces el inicio de sesión con una contraseña en blanco estará permitido, pero no se podrá publicar en la sala. (solo lectura).'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Establece el número máximo de saltos de paquetes de inundación entrantes (si es >= máximo, el paquete no se enruta).'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Establece el Umbral de Interferencia (en dB). El valor predeterminado es 14. Establecerlo en 0 desactiva la detección de interferencias del canal.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Establece el intervalo para restablecer el Control Automático de Ganancia. Establecer en 0 para desactivarlo.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Habilita o deshabilita la función de \'ACKs dobles\'.'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Establece el intervalo del temporizador en minutos para enviar un paquete de anuncio local (sin salto). Establecer en 0 para desactivarlo.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Establece el intervalo del temporizador en horas para enviar un paquete de anuncio masivo. Establecer en 0 para desactivarlo.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Establece/actualiza la contraseña del invitado. (para repetidores, los inicios de sesión de invitado pueden enviar la solicitud \"Obtener Estadísticas\")'; + + @override + String get repeater_cliHelpSetName => 'Establece el nombre del anuncio.'; + + @override + String get repeater_cliHelpSetLat => + 'Establece la latitud del mapa de publicidad. (grados decimales)'; + + @override + String get repeater_cliHelpSetLon => + 'Establece la longitud del mapa de la publicidad. (grados decimales)'; + + @override + String get repeater_cliHelpSetRadio => + 'Establece parámetros de radio completamente nuevos y los guarda en las preferencias. Requiere un comando \"reboot\" para aplicarlos.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Configura (experimental) la base para aplicar un ligero retraso a los paquetes recibidos, según la fuerza de la señal/puntuación. Establece en 0 para desactivar.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Establece un factor multiplicado con el tiempo de aire para un paquete de modo de inundación y con un sistema de ranura aleatorio, para retrasar su reenvío (para disminuir la probabilidad de colisiones).'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Igual que txdelay, pero para aplicar un retraso aleatorio a la transferencia de paquetes en modo directo.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => + 'Habilitar/Deshabilitar puente.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Establecer retraso antes de retransmitir paquetes.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Elige si el puente retransmitirá paquetes recibidos o paquetes transmitidos.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Establecer la velocidad de baudios del enlace serial para los puentes rs232.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Establecer secreto de puente para puentes espnow.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Establece un factor personalizado para ajustar el voltaje de la batería reportado (solo soportado en selectas placas).'; + + @override + String get repeater_cliHelpTempRadio => + 'Establece parámetros de radio temporales para el número dado de minutos, volviendo a los parámetros de radio originales posteriormente. (no guarda en preferencias).'; + + @override + String get repeater_cliHelpSetPerm => + 'Modifica el ACL. Elimina la entrada coincidente (por prefijo de pubkey) si \"permissions\" es cero. Añade una nueva entrada si el pubkey-hex tiene longitud completa y no está actualmente en el ACL. Actualiza la entrada mediante el prefijo de pubkey coincidente. Los bits de permiso varían según el rol del firmware, pero los dos bits inferiores son: 0 (Invitado), 1 (Solo lectura), 2 (Lectura/escritura), 3 (Administrador).'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Obtiene tipo de puente ninguno, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => + 'Inicia el registro de paquetes en el sistema de archivos.'; + + @override + String get repeater_cliHelpLogStop => + 'Detener el registro de paquetes al sistema de archivos.'; + + @override + String get repeater_cliHelpLogErase => + 'Elimina los registros del paquete del sistema de archivos.'; + + @override + String get repeater_cliHelpNeighbors => + 'Muestra una lista de otros nodos repetidores escuchados a través de anuncios de un solo salto. Cada línea es id-prefijo-hex:marca de tiempo:times-snr-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Elimina la primera entrada coincidente (por prefijo de pubkey (hex)) de la lista de vecinos.'; + + @override + String get repeater_cliHelpRegion => + '(solo serie) Lista todas las regiones definidas y los permisos de inundación actuales.'; + + @override + String get repeater_cliHelpRegionLoad => + 'NOTA: este es un invocación multi-comando especial. Cada comando subsiguiente es un nombre de región (indentado con espacios para indicar la jerarquía padre, con un espacio mínimo). Terminado enviando una línea en blanco/comando.'; + + @override + String get repeater_cliHelpRegionGet => + 'Busca la región con el prefijo de nombre dado (o \"\" para el ámbito global). Responde con \"-> nombre-región (nombre-padre) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Agrega o actualiza una definición de región con el nombre dado.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Elimina una definición de región con el nombre dado. (debe coincidir exactamente y no tener regiones hijas)'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Establece el permiso de \'F\'lujo para la región dada. (\'\' para el ámbito global/legado)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Elimina el permiso de \'F\'lood para la región especificada. (NOTA: en esta etapa NO se recomienda utilizarlo en el ámbito global/legado!!)'; + + @override + String get repeater_cliHelpRegionHome => + 'Responde con la región \'home\' actual. (Aún no se ha aplicado en ninguna parte, reservado para el futuro).'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Establece la región \'hogar\'.'; + + @override + String get repeater_cliHelpRegionSave => + 'Persiste la lista/mapa de regiones al almacenamiento.'; + + @override + String get repeater_cliHelpGps => + 'Muestra el estado del GPS. Cuando el GPS está apagado, responde solo con \"apagado\", si está encendido, responde con \"encendido\", estado, fijación, número de satélites.'; + + @override + String get repeater_cliHelpGpsOnOff => 'Activa o desactiva el modo GPS.'; + + @override + String get repeater_cliHelpGpsSync => + 'Sincroniza la hora del nodo con el reloj GPS.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Establece la posición del nodo a las coordenadas GPS y guarda las preferencias.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Da la configuración de la publicidad del nodo de ubicación:\n- ninguno: no incluir la ubicación en las publicidad\n- compartir: compartir la ubicación GPS (del SensorManager)\n- preferencias: publicidad la ubicación almacenada en preferencias'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Configura la configuración de la publicidad de la ubicación.'; + + @override + String get repeater_commandsListTitle => 'Lista de comandos'; + + @override + String get repeater_commandsListNote => + 'NOTA: para los diversos comandos \"set...\", también existe un comando \"get...\".'; + + @override + String get repeater_general => 'General'; + + @override + String get repeater_settingsCategory => 'Configuración'; + + @override + String get repeater_bridge => 'Puente'; + + @override + String get repeater_logging => 'Registrando'; + + @override + String get repeater_neighborsRepeaterOnly => 'Vecinos (solo repetidor)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Gestión de Regiones (solo Repetidor)'; + + @override + String get repeater_regionNote => + 'Se han introducido los comandos de región para gestionar las definiciones y permisos de la región.'; + + @override + String get repeater_gpsManagement => 'Gestión de GPS'; + + @override + String get repeater_gpsNote => + 'Se ha introducido un comando GPS para gestionar temas relacionados con la ubicación.'; + + @override + String get telemetry_receivedData => 'Datos de Telemetría Recibidos'; + + @override + String get telemetry_requestTimeout => 'Solicitud de telemetría ha expirado.'; + + @override + String telemetry_errorLoading(String error) { + return 'Error al cargar la telemetría: $error'; + } + + @override + String get telemetry_noData => 'No hay datos de telemetría disponibles.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Canal $channel'; + } + + @override + String get telemetry_batteryLabel => 'Batería'; + + @override + String get telemetry_voltageLabel => 'Voltaje'; + + @override + String get telemetry_mcuTemperatureLabel => 'Temperatura del MCU'; + + @override + String get telemetry_temperatureLabel => 'Temperatura'; + + @override + String get telemetry_currentLabel => 'Actual'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Ruta del Paquete'; + + @override + String get channelPath_viewMap => 'Ver mapa'; + + @override + String get channelPath_otherObservedPaths => 'Otros caminos observados'; + + @override + String get channelPath_repeaterHops => 'Saltos del Repetidor'; + + @override + String get channelPath_noHopDetails => + 'Los detalles del paquete no están disponibles.'; + + @override + String get channelPath_messageDetails => 'Detalles del mensaje'; + + @override + String get channelPath_senderLabel => 'Remitente'; + + @override + String get channelPath_timeLabel => 'Tiempo'; + + @override + String get channelPath_repeatsLabel => 'Repetir'; + + @override + String channelPath_pathLabel(int index) { + return 'Ruta $index'; + } + + @override + String get channelPath_observedLabel => 'Observado'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Ruta observada $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'No datos de ubicación'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month a las $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Desconocido'; + + @override + String get channelPath_floodPath => 'Inundación'; + + @override + String get channelPath_directPath => 'Guardar'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 de $total saltos'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed de $total saltos'; + } + + @override + String get channelPath_mapTitle => 'Mapa de Rutas'; + + @override + String get channelPath_noRepeaterLocations => + 'No hay ubicaciones disponibles para el repetidor en esta ruta.'; + + @override + String channelPath_primaryPath(int index) { + return 'Ruta $index (Principal)'; + } + + @override + String get channelPath_pathLabelTitle => 'Ruta'; + + @override + String get channelPath_observedPathHeader => 'Ruta Observada'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'No hay detalles de salto disponibles para este paquete.'; + + @override + String get channelPath_unknownRepeater => 'Repetidor Desconocido'; + + @override + String get listFilter_tooltip => 'Filtrar y ordenar'; + + @override + String get listFilter_sortBy => 'Ordenar por'; + + @override + String get listFilter_latestMessages => 'Últimos mensajes'; + + @override + String get listFilter_heardRecently => 'Escuchado recientemente'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Filtros'; + + @override + String get listFilter_all => 'Todas'; + + @override + String get listFilter_users => 'Usuarios'; + + @override + String get listFilter_repeaters => 'Repetidores'; + + @override + String get listFilter_roomServers => 'Servidores de la sala'; + + @override + String get listFilter_unreadOnly => 'Solo sin leer'; + + @override + String get listFilter_newGroup => 'Nuevo grupo'; +} diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart new file mode 100644 index 0000000..acdb5b0 --- /dev/null +++ b/lib/l10n/app_localizations_fr.dart @@ -0,0 +1,2402 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for French (`fr`). +class AppLocalizationsFr extends AppLocalizations { + AppLocalizationsFr([String locale = 'fr']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Contacts'; + + @override + String get nav_channels => 'Canaux'; + + @override + String get nav_map => 'Carte'; + + @override + String get common_cancel => 'Annuler'; + + @override + String get common_connect => 'Connecter'; + + @override + String get common_unknownDevice => 'Appareil inconnu'; + + @override + String get common_save => 'Enregistrer'; + + @override + String get common_delete => 'Supprimer'; + + @override + String get common_close => 'Fermer'; + + @override + String get common_edit => 'Modifier'; + + @override + String get common_add => 'Ajouter'; + + @override + String get common_settings => 'Paramètres'; + + @override + String get common_disconnect => 'Déconnecter'; + + @override + String get common_connected => 'Connecté'; + + @override + String get common_disconnected => 'Déconnecté'; + + @override + String get common_create => 'Créer'; + + @override + String get common_continue => 'Continuer'; + + @override + String get common_share => 'Partager'; + + @override + String get common_copy => 'Copier'; + + @override + String get common_retry => 'Réessayer'; + + @override + String get common_hide => 'Masquer'; + + @override + String get common_remove => 'Supprimer'; + + @override + String get common_enable => 'Activer'; + + @override + String get common_disable => 'Désactiver'; + + @override + String get common_reboot => 'Redémarrer'; + + @override + String get common_loading => 'Chargement...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Recherche de périphériques...'; + + @override + String get scanner_connecting => 'Connexion en cours...'; + + @override + String get scanner_disconnecting => 'Déconnexion...'; + + @override + String get scanner_notConnected => 'Non connecté'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Connecté à $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Recherche des appareils MeshCore...'; + + @override + String get scanner_tapToScan => + 'Appuyez sur Scanner pour trouver les appareils MeshCore'; + + @override + String scanner_connectionFailed(String error) { + return 'Échec de la connexion : $error'; + } + + @override + String get scanner_stop => 'Arrêter'; + + @override + String get scanner_scan => 'Scanner'; + + @override + String get device_quickSwitch => 'Basculement rapide'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Paramètres'; + + @override + String get settings_deviceInfo => 'Informations du périphérique'; + + @override + String get settings_appSettings => 'Paramètres de l\'application'; + + @override + String get settings_appSettingsSubtitle => + 'Notifications, messagerie et préférences de carte'; + + @override + String get settings_nodeSettings => 'Paramètres du nœud'; + + @override + String get settings_nodeName => 'Nom du nœud'; + + @override + String get settings_nodeNameNotSet => 'Non défini'; + + @override + String get settings_nodeNameHint => 'Entrer le nom du nœud'; + + @override + String get settings_nodeNameUpdated => 'Nom mis à jour'; + + @override + String get settings_radioSettings => 'Paramètres Radio'; + + @override + String get settings_radioSettingsSubtitle => + 'Fréquence, puissance, facteur d\'espacement'; + + @override + String get settings_radioSettingsUpdated => 'Paramètres radio mis à jour'; + + @override + String get settings_location => 'Emplacement'; + + @override + String get settings_locationSubtitle => 'Coordonnées GPS'; + + @override + String get settings_locationUpdated => 'Emplacement mis à jour'; + + @override + String get settings_locationBothRequired => + 'Entrez la latitude et la longitude.'; + + @override + String get settings_locationInvalid => 'Latitude ou longitude invalide.'; + + @override + String get settings_latitude => 'Latitude'; + + @override + String get settings_longitude => 'Longitude'; + + @override + String get settings_privacyMode => 'Mode de confidentialité'; + + @override + String get settings_privacyModeSubtitle => + 'Cacher le nom/l\'emplacement dans les publicités'; + + @override + String get settings_privacyModeToggle => + 'Activer le mode confidentialité pour masquer votre nom et votre localisation dans les publicités.'; + + @override + String get settings_privacyModeEnabled => 'Mode de confidentialité activé'; + + @override + String get settings_privacyModeDisabled => + 'Mode de confidentialité désactivé'; + + @override + String get settings_actions => 'Actions'; + + @override + String get settings_sendAdvertisement => 'Envoyer la publicité'; + + @override + String get settings_sendAdvertisementSubtitle => + 'Présence diffusée maintenant'; + + @override + String get settings_advertisementSent => 'Annonce envoyée'; + + @override + String get settings_syncTime => 'Temps de synchronisation'; + + @override + String get settings_syncTimeSubtitle => + 'Définir l\'heure de l\'appareil sur l\'heure du téléphone.'; + + @override + String get settings_timeSynchronized => 'Synchronisation temporelle'; + + @override + String get settings_refreshContacts => 'Rafraîchir les Contacts'; + + @override + String get settings_refreshContactsSubtitle => + 'Recharger la liste des contacts depuis l\'appareil'; + + @override + String get settings_rebootDevice => 'Réinitialiser l\'appareil'; + + @override + String get settings_rebootDeviceSubtitle => 'Redémarrer l\'appareil MeshCore'; + + @override + String get settings_rebootDeviceConfirm => + 'Êtes-vous sûr de vouloir redémarrer l\'appareil ? Vous serez déconnecté.'; + + @override + String get settings_debug => 'Déboguer'; + + @override + String get settings_bleDebugLog => 'Journal de débogage BLE'; + + @override + String get settings_bleDebugLogSubtitle => + 'Commandes BLE, réponses et données brutes'; + + @override + String get settings_appDebugLog => 'Journal de débogage de l\'application'; + + @override + String get settings_appDebugLogSubtitle => + 'Messages de débogage de l\'application'; + + @override + String get settings_about => 'À propos'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => 'Projet MeshCore Open Source 2026'; + + @override + String get settings_aboutDescription => + 'Un client Flutter open source pour les appareils de réseau mesh MeshCore LoRa.'; + + @override + String get settings_infoName => 'Nom'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'État'; + + @override + String get settings_infoBattery => 'Batterie'; + + @override + String get settings_infoPublicKey => 'Clé Publique'; + + @override + String get settings_infoContactsCount => 'Nombre de contacts'; + + @override + String get settings_infoChannelCount => 'Nombre de canaux'; + + @override + String get settings_presets => 'Préréglages'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Fréquence (MHz)'; + + @override + String get settings_frequencyHelper => '300,0 - 2 500,0'; + + @override + String get settings_frequencyInvalid => 'Fréquence invalide (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Bande passante'; + + @override + String get settings_spreadingFactor => 'Facteur de répartition'; + + @override + String get settings_codingRate => 'Taux de codage'; + + @override + String get settings_txPower => 'TX Puissance (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Puissance TX invalide (0-22 dBm)'; + + @override + String get settings_longRange => 'Portée Longue'; + + @override + String get settings_fastSpeed => 'Vitesse Rapide'; + + @override + String settings_error(String message) { + return 'Erreur : $message'; + } + + @override + String get appSettings_title => 'Paramètres de l\'application'; + + @override + String get appSettings_appearance => 'Apparence'; + + @override + String get appSettings_theme => 'Thème'; + + @override + String get appSettings_themeSystem => 'Défaut système'; + + @override + String get appSettings_themeLight => 'Lumière'; + + @override + String get appSettings_themeDark => 'Sombre'; + + @override + String get appSettings_language => 'Langue'; + + @override + String get appSettings_languageSystem => 'Par défaut du système'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Notifications'; + + @override + String get appSettings_enableNotifications => 'Activer les Notifications'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Recevoir des notifications pour les messages et les publicités'; + + @override + String get appSettings_notificationPermissionDenied => + 'Permission de notification refusée'; + + @override + String get appSettings_notificationsEnabled => 'Notifications activées'; + + @override + String get appSettings_notificationsDisabled => 'Notifications désactivées'; + + @override + String get appSettings_messageNotifications => 'Notifications de Messages'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Afficher une notification lors de la réception de nouveaux messages'; + + @override + String get appSettings_channelMessageNotifications => + 'Notifications des Messages de Canal'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Afficher une notification lors de la réception des messages de canal'; + + @override + String get appSettings_advertisementNotifications => + 'Notifications publicitaires'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Afficher une notification lors de la découverte de nouveaux nœuds'; + + @override + String get appSettings_messaging => 'Messagerie'; + + @override + String get appSettings_clearPathOnMaxRetry => + 'Effacer le chemin sur Max Retry'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Réinitialiser le chemin de contact après 5 tentatives d\'envoi infructueuses'; + + @override + String get appSettings_pathsWillBeCleared => + 'Les chemins seront effacés après 5 tentatives infructueuses.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Les chemins ne seront pas effacés automatiquement.'; + + @override + String get appSettings_autoRouteRotation => + 'Rotation de l\'itinéraire automatique'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Alterner entre les meilleurs chemins et le mode inondation'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Rotation du routage automatique activée'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Rotation de l\'itinéraire automatique désactivée'; + + @override + String get appSettings_battery => 'Batterie'; + + @override + String get appSettings_batteryChemistry => 'Chimie de la batterie'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Définir par appareil ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Connectez un appareil pour choisir'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6-3,65V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + + @override + String get appSettings_mapDisplay => 'Affichage de la carte'; + + @override + String get appSettings_showRepeaters => 'Afficher les répétiteurs'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Afficher les nœuds répétiteurs sur la carte'; + + @override + String get appSettings_showChatNodes => 'Afficher les nœuds de discussion'; + + @override + String get appSettings_showChatNodesSubtitle => + 'Afficher les nœuds de chat sur la carte'; + + @override + String get appSettings_showOtherNodes => 'Afficher d\'autres nœuds'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Afficher d\'autres types de nœuds sur la carte'; + + @override + String get appSettings_timeFilter => 'Filtre du temps'; + + @override + String get appSettings_timeFilterShowAll => 'Afficher tous les nœuds'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Afficher les nœuds des $hours dernières heures'; + } + + @override + String get appSettings_mapTimeFilter => 'Filtre du Temps de la Carte'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Afficher les nœuds découverts dans :'; + + @override + String get appSettings_allTime => 'Tout le temps'; + + @override + String get appSettings_lastHour => 'Dernière heure'; + + @override + String get appSettings_last6Hours => 'Dernières 6 heures'; + + @override + String get appSettings_last24Hours => 'Dernières 24 heures'; + + @override + String get appSettings_lastWeek => 'La semaine dernière'; + + @override + String get appSettings_offlineMapCache => 'Cache de Carte Hors Ligne'; + + @override + String get appSettings_noAreaSelected => 'Aucune zone sélectionnée'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Zone sélectionnée (zoom $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Déboguer'; + + @override + String get appSettings_appDebugLogging => + 'Journalisation de débogage de l\'application'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Enregistrez les messages de débogage de l\'application Log pour le dépannage.'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'Journalisation de débogage de l\'application activée'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'Le débogage de l\'application est désactivé.'; + + @override + String get contacts_title => 'Contacts'; + + @override + String get contacts_noContacts => 'Aucun contact trouvé.'; + + @override + String get contacts_contactsWillAppear => + 'Les contacts apparaîtront lorsque les appareils font leur annonce.'; + + @override + String get contacts_searchContacts => 'Rechercher des contacts...'; + + @override + String get contacts_noUnreadContacts => 'Aucun contact non lu'; + + @override + String get contacts_noContactsFound => 'Aucun contact ou groupe trouvé.'; + + @override + String get contacts_deleteContact => 'Supprimer le contact'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Supprimer $contactName des contacts ?'; + } + + @override + String get contacts_manageRepeater => 'Gérer le répétiteur'; + + @override + String get contacts_roomLogin => 'Connexion Salle'; + + @override + String get contacts_openChat => 'Ouverture du Chat'; + + @override + String get contacts_editGroup => 'Modifier le groupe'; + + @override + String get contacts_deleteGroup => 'Supprimer le groupe'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Supprimer $groupName?'; + } + + @override + String get contacts_newGroup => 'Nouvelle Groupe'; + + @override + String get contacts_groupName => 'Nom du groupe'; + + @override + String get contacts_groupNameRequired => 'Le nom du groupe est obligatoire.'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'Le groupe \"$name\" existe déjà.'; + } + + @override + String get contacts_filterContacts => 'Filtrer les contacts...'; + + @override + String get contacts_noContactsMatchFilter => + 'Aucun contact ne correspond à votre filtre.'; + + @override + String get contacts_noMembers => 'Aucun membre'; + + @override + String get contacts_lastSeenNow => 'Dernière fois vu maintenant'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Dernière fois vu il y a $minutes minutes.'; + } + + @override + String get contacts_lastSeenHourAgo => 'Dernière fois vu il y a 1 heure.'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Dernière fois vu il y a $hours heures.'; + } + + @override + String get contacts_lastSeenDayAgo => 'Dernière fois vu il y a 1 jour'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Dernière activité il y a $days jours'; + } + + @override + String get channels_title => 'Canaux'; + + @override + String get channels_noChannelsConfigured => 'Aucun canal configuré'; + + @override + String get channels_addPublicChannel => 'Ajouter un canal public'; + + @override + String get channels_searchChannels => 'Rechercher des canaux...'; + + @override + String get channels_noChannelsFound => 'Aucun canal trouvé'; + + @override + String channels_channelIndex(int index) { + return 'Canal $index'; + } + + @override + String get channels_hashtagChannel => 'Canal avec hashtag'; + + @override + String get channels_public => 'Public'; + + @override + String get channels_private => 'Privé'; + + @override + String get channels_publicChannel => 'Canal public'; + + @override + String get channels_privateChannel => 'Canal privé'; + + @override + String get channels_editChannel => 'Modifier le canal'; + + @override + String get channels_deleteChannel => 'Supprimer le canal'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Supprimer $name? Cela ne peut pas être annulé.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Le canal \"$name\" a été supprimé'; + } + + @override + String get channels_addChannel => 'Ajouter un Canal'; + + @override + String get channels_channelIndexLabel => 'Index de canal'; + + @override + String get channels_channelName => 'Nom du canal'; + + @override + String get channels_usePublicChannel => 'Utiliser le canal public'; + + @override + String get channels_standardPublicPsk => 'PSK public standard'; + + @override + String get channels_pskHex => 'PSK (Hex)'; + + @override + String get channels_generateRandomPsk => + 'Générer une clé de modulation PSK aléatoire'; + + @override + String get channels_enterChannelName => 'Veuillez entrer un nom de canal'; + + @override + String get channels_pskMustBe32Hex => + 'Le PKS doit être composé de 32 caractères hexadécimaux.'; + + @override + String channels_channelAdded(String name) { + return 'Le canal \"$name\" a été ajouté'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Modifier le Canal $index'; + } + + @override + String get channels_smazCompression => 'Compression SMAZ'; + + @override + String channels_channelUpdated(String name) { + return 'Le canal \"$name\" a été mis à jour'; + } + + @override + String get channels_publicChannelAdded => 'Le canal public a été ajouté'; + + @override + String get channels_sortBy => 'Trier par'; + + @override + String get channels_sortManual => 'Manuel'; + + @override + String get channels_sortAZ => 'A à Z'; + + @override + String get channels_sortLatestMessages => 'Dernières messages'; + + @override + String get channels_sortUnread => 'Non lu'; + + @override + String get chat_noMessages => 'Aucun message pour le moment.'; + + @override + String get chat_sendMessageToStart => 'Envoyer un message pour commencer'; + + @override + String get chat_originalMessageNotFound => 'Message d\'origine non trouvé'; + + @override + String chat_replyingTo(String name) { + return 'Répondre à $name'; + } + + @override + String chat_replyTo(String name) { + return 'Répondre à $name'; + } + + @override + String get chat_location => 'Emplacement'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Envoyer un message à $contactName'; + } + + @override + String get chat_typeMessage => 'Saisir un message...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Message trop long (max $maxBytes octets).'; + } + + @override + String get chat_messageCopied => 'Message copié'; + + @override + String get chat_messageDeleted => 'Message supprimé'; + + @override + String get chat_retryingMessage => 'Tentative de récupération.'; + + @override + String chat_retryCount(int current, int max) { + return 'Réessayer $current/$max'; + } + + @override + String get chat_sendGif => 'Envoyer GIF'; + + @override + String get chat_reply => 'Répondre'; + + @override + String get chat_addReaction => 'Ajouter une Réaction'; + + @override + String get chat_me => 'Moi'; + + @override + String get emojiCategorySmileys => 'Émojis'; + + @override + String get emojiCategoryGestures => 'Gestes'; + + @override + String get emojiCategoryHearts => 'Cœurs'; + + @override + String get emojiCategoryObjects => 'Objets'; + + @override + String get gifPicker_title => 'Choisir un GIF'; + + @override + String get gifPicker_searchHint => 'Rechercher des GIF...'; + + @override + String get gifPicker_poweredBy => 'Propulsé par GIPHY'; + + @override + String get gifPicker_noGifsFound => 'Aucun GIF trouvé'; + + @override + String get gifPicker_failedLoad => 'Impossible de charger les GIFs'; + + @override + String get gifPicker_failedSearch => 'Recherche de GIFs échouée'; + + @override + String get gifPicker_noInternet => 'Aucune connexion internet'; + + @override + String get debugLog_appTitle => 'Journal de débogage de l\'application'; + + @override + String get debugLog_bleTitle => 'Journal de débogage BLE'; + + @override + String get debugLog_copyLog => 'Copier le journal'; + + @override + String get debugLog_clearLog => 'Effacer le journal'; + + @override + String get debugLog_copied => 'Journal de débogage copié'; + + @override + String get debugLog_bleCopied => 'Journal BLE copié'; + + @override + String get debugLog_noEntries => 'Aucun journal de débogage pour le moment.'; + + @override + String get debugLog_enableInSettings => + 'Activer le débogage de l\'application dans les paramètres'; + + @override + String get debugLog_frames => 'Cadres'; + + @override + String get debugLog_rawLogRx => 'Enregistrement brut - RX'; + + @override + String get debugLog_noBleActivity => + 'Pas d\'activité BLE enregistrée pour le moment.'; + + @override + String debugFrame_length(int count) { + return 'Longueur du cadre : $count octets'; + } + + @override + String debugFrame_command(String value) { + return 'Commande : 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Message :'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Destination PubKey: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Timestamp : $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Indicateurs : 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Type de texte : $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Simple'; + + @override + String debugFrame_text(String text) { + return '- Texte : \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Vidéo de Dump Hexadécimal :'; + + @override + String get chat_pathManagement => 'Gestion des chemins'; + + @override + String get chat_routingMode => 'Mode de routage'; + + @override + String get chat_autoUseSavedPath => 'Auto (utiliser le chemin sauvegardé)'; + + @override + String get chat_forceFloodMode => 'Mode Inondation Forcée'; + + @override + String get chat_recentAckPaths => + 'Chemins ACK récents (touchez pour utiliser) :'; + + @override + String get chat_pathHistoryFull => + 'L\'historique du chemin est plein. Supprimez les entrées pour en ajouter de nouvelles.'; + + @override + String get chat_hopSingular => 'Sautez'; + + @override + String get chat_hopPlural => 'sautez'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'Succès'; + + @override + String get chat_removePath => 'Supprimer le chemin'; + + @override + String get chat_noPathHistoryYet => + 'Aucune historique de parcours disponible.\nEnvoyez un message pour découvrir les parcours.'; + + @override + String get chat_pathActions => 'Actions du chemin :'; + + @override + String get chat_setCustomPath => 'Définir un chemin personnalisé'; + + @override + String get chat_setCustomPathSubtitle => + 'Spécifier manuellement le chemin de routage'; + + @override + String get chat_clearPath => 'Effacer le chemin'; + + @override + String get chat_clearPathSubtitle => + 'Forcer la redécouverte lors de la prochaine envoi'; + + @override + String get chat_pathCleared => + 'Le chemin est dégagé. Le prochain message redécouvrira le tracé.'; + + @override + String get chat_floodModeSubtitle => + 'Utiliser le commutateur de routage dans la barre d\'application'; + + @override + String get chat_floodModeEnabled => + 'Le mode inondation est activé. Réactiver via l\'icône de routage dans la barre d\'outils.'; + + @override + String get chat_fullPath => 'Chemin complet'; + + @override + String get chat_pathDetailsNotAvailable => + 'Les détails du chemin ne sont pas encore disponibles. Essayez d\'envoyer un message pour rafraîchir.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Chemin défini : $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Sauvegardé localement. Connectez-vous pour synchroniser.'; + + @override + String get chat_pathDeviceConfirmed => 'Appareil confirmé.'; + + @override + String get chat_pathDeviceNotConfirmed => + 'L\'appareil n\'a pas encore été confirmé.'; + + @override + String get chat_type => 'Saisir'; + + @override + String get chat_path => 'Chemin'; + + @override + String get chat_publicKey => 'Clé Publique'; + + @override + String get chat_compressOutgoingMessages => + 'Compresser les messages sortants'; + + @override + String get chat_floodForced => 'Inondation (forcée)'; + + @override + String get chat_directForced => 'Direct (forcé)'; + + @override + String chat_hopsForced(int count) { + return '$count sauts (forcés)'; + } + + @override + String get chat_floodAuto => 'Inondation (auto)'; + + @override + String get chat_direct => 'Afficher'; + + @override + String get chat_poiShared => 'Point d\'intérêt Partagé'; + + @override + String chat_unread(int count) { + return 'Non lu : $count'; + } + + @override + String get map_title => 'Carte des nœuds'; + + @override + String get map_noNodesWithLocation => + 'Aucun nœud avec des données de localisation'; + + @override + String get map_nodesNeedGps => + 'Les nœuds doivent partager leurs coordonnées GPS\npour apparaître sur la carte.'; + + @override + String map_nodesCount(int count) { + return 'Nœuds : $count'; + } + + @override + String map_pinsCount(int count) { + return 'Epingles: $count'; + } + + @override + String get map_chat => 'Chat'; + + @override + String get map_repeater => 'Répétiteur'; + + @override + String get map_room => 'Salle'; + + @override + String get map_sensor => 'Capteur'; + + @override + String get map_pinDm => 'Clé (DM)'; + + @override + String get map_pinPrivate => 'Verrouiller (Privé)'; + + @override + String get map_pinPublic => 'Clé (Public)'; + + @override + String get map_lastSeen => 'Dernière fois vu'; + + @override + String get map_disconnectConfirm => + 'Êtes-vous sûr de vouloir vous déconnecter de cet appareil ?'; + + @override + String get map_from => 'À partir de'; + + @override + String get map_source => 'Source'; + + @override + String get map_flags => 'Drapeaux'; + + @override + String get map_shareMarkerHere => 'Partager le marqueur ici'; + + @override + String get map_pinLabel => 'Étiquete de repin'; + + @override + String get map_label => 'Étiquette'; + + @override + String get map_pointOfInterest => 'Point d\'intérêt'; + + @override + String get map_sendToContact => 'Envoyer au contact'; + + @override + String get map_sendToChannel => 'Envoyer sur le canal'; + + @override + String get map_noChannelsAvailable => 'Aucun canal disponible'; + + @override + String get map_publicLocationShare => 'Partager dans un lieu public'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'Vous êtes sur le point de partager un emplacement dans $channelLabel. Ce canal est public et toute personne disposant de la clé PSK peut le voir.'; + } + + @override + String get map_connectToShareMarkers => + 'Connectez-vous à un appareil pour partager des marqueurs'; + + @override + String get map_filterNodes => 'Filtrer les nœuds'; + + @override + String get map_nodeTypes => 'Types de nœuds'; + + @override + String get map_chatNodes => 'Nœuds de Chat'; + + @override + String get map_repeaters => 'Répéteurs'; + + @override + String get map_otherNodes => 'Autres nœuds'; + + @override + String get map_keyPrefix => 'Préfixe clé'; + + @override + String get map_filterByKeyPrefix => 'Filtrer par préfixe de clé'; + + @override + String get map_publicKeyPrefix => 'Préfixe de clé publique'; + + @override + String get map_markers => 'Marqueurs'; + + @override + String get map_showSharedMarkers => 'Afficher les marqueurs partagés'; + + @override + String get map_lastSeenTime => 'Dernière fois vu'; + + @override + String get map_sharedPin => 'Clé partagée'; + + @override + String get map_joinRoom => 'Rejoindre la salle'; + + @override + String get map_manageRepeater => 'Gérer le répétiteur'; + + @override + String get mapCache_title => 'Cache de Carte Hors Ligne'; + + @override + String get mapCache_selectAreaFirst => + 'Sélectionner une zone pour la mise en cache en premier'; + + @override + String get mapCache_noTilesToDownload => + 'Aucun tuilage à télécharger pour cette zone.'; + + @override + String get mapCache_downloadTilesTitle => 'Télécharger les tuiles'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Télécharger $count tuiles pour un usage hors ligne ?'; + } + + @override + String get mapCache_downloadAction => 'Télécharger'; + + @override + String mapCache_cachedTiles(int count) { + return 'Cachez $count tuiles'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Tiles mis en cache ($downloaded) ($failed ratés)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => 'Vider le cache hors ligne'; + + @override + String get mapCache_clearOfflineCachePrompt => + 'Supprimer toutes les tuiles de carte mises en cache ?'; + + @override + String get mapCache_offlineCacheCleared => + 'Le cache hors ligne a été effacé.'; + + @override + String get mapCache_noAreaSelected => 'Aucune zone sélectionnée'; + + @override + String get mapCache_cacheArea => 'Zone de cache'; + + @override + String get mapCache_useCurrentView => 'Utiliser la Vue Actuelle'; + + @override + String get mapCache_zoomRange => 'Plage de zoom'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Estimation des tuiles : $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Téléchargé $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Télécharger les tuiles'; + + @override + String get mapCache_clearCacheButton => 'Vider le Cache'; + + @override + String mapCache_failedDownloads(int count) { + return 'Téléchargements échoués : $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Il y a tout juste maintenant'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes minutes auparavant'; + } + + @override + String time_hoursAgo(int hours) { + return '${hours}h auparavant'; + } + + @override + String time_daysAgo(int days) { + return '$days jours avant'; + } + + @override + String get time_hour => 'heure'; + + @override + String get time_hours => 'heures'; + + @override + String get time_day => 'jour'; + + @override + String get time_days => 'jours'; + + @override + String get time_week => 'semaine'; + + @override + String get time_weeks => 'semaines'; + + @override + String get time_month => 'mois'; + + @override + String get time_months => 'mois'; + + @override + String get time_minutes => 'minutes'; + + @override + String get time_allTime => 'Tout le temps'; + + @override + String get dialog_disconnect => 'Déconnecter'; + + @override + String get dialog_disconnectConfirm => + 'Êtes-vous sûr de vouloir vous déconnecter de cet appareil ?'; + + @override + String get login_repeaterLogin => 'Connexion au répétiteur'; + + @override + String get login_roomLogin => 'Connexion Salle'; + + @override + String get login_password => 'Mot de passe'; + + @override + String get login_enterPassword => 'Entrez votre mot de passe'; + + @override + String get login_savePassword => 'Sauvegarder le mot de passe'; + + @override + String get login_savePasswordSubtitle => + 'Le mot de passe sera stocké en toute sécurité sur cet appareil.'; + + @override + String get login_repeaterDescription => + 'Entrez le mot de passe du répétiteur pour accéder aux paramètres et à l\'état.'; + + @override + String get login_roomDescription => + 'Entrez le mot de passe de la pièce pour accéder aux paramètres et à l\'état.'; + + @override + String get login_routing => 'Redirection'; + + @override + String get login_routingMode => 'Mode de routage'; + + @override + String get login_autoUseSavedPath => 'Auto (utiliser le chemin sauvegardé)'; + + @override + String get login_forceFloodMode => 'Mode Inondation Forcée'; + + @override + String get login_managePaths => 'Gérer les chemins'; + + @override + String get login_login => 'Connexion'; + + @override + String login_attempt(int current, int max) { + return 'Essayer $current/$max'; + } + + @override + String login_failed(String error) { + return 'Connexion échouée : $error'; + } + + @override + String get common_reload => 'Recharger'; + + @override + String get common_clear => 'Effacer'; + + @override + String path_currentPath(String path) { + return 'Chemin actuel : $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Utiliser $count $_temp0 chemin'; + } + + @override + String get path_enterCustomPath => 'Entrer un chemin personnalisé'; + + @override + String get path_currentPathLabel => 'Chemin actuel'; + + @override + String get path_hexPrefixInstructions => + 'Entrez les préfixes hexadécimaux de 2 caractères pour chaque saut, séparés par des virgules.'; + + @override + String get path_hexPrefixExample => + 'Exemple : A1,F2,3C (chaque nœud utilise le premier octet de sa clé publique).'; + + @override + String get path_labelHexPrefixes => 'Préfixes hexadécimaux'; + + @override + String get path_helperMaxHops => + 'Max 64 sauts. Chaque préfixe fait 2 caractères hexadécimaux (1 octet)'; + + @override + String get path_selectFromContacts => 'Sélectionner à partir des contacts :'; + + @override + String get path_noRepeatersFound => + 'Aucun répéteur ou serveur de salle n\'a été trouvé.'; + + @override + String get path_customPathsRequire => + 'Les chemins personnalisés nécessitent des sauts intermédiaires qui peuvent transmettre des messages.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Préfixes hexadécimaux invalides : $prefixes'; + } + + @override + String get path_tooLong => + 'Le chemin est trop long. Maximum 64 sauts autorisés.'; + + @override + String get path_setPath => 'Définir le chemin'; + + @override + String get repeater_management => 'Gestion des répétiteurs'; + + @override + String get repeater_managementTools => 'Outils de Gestion'; + + @override + String get repeater_status => 'État'; + + @override + String get repeater_statusSubtitle => + 'Afficher l\'état, les statistiques et les voisins du répétiteur'; + + @override + String get repeater_telemetry => 'Télémetrie'; + + @override + String get repeater_telemetrySubtitle => + 'Afficher la télémétrie des capteurs et les statistiques du système'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Envoyer des commandes au répétiteur'; + + @override + String get repeater_settings => 'Paramètres'; + + @override + String get repeater_settingsSubtitle => + 'Configurer les paramètres du répétiteur'; + + @override + String get repeater_statusTitle => 'État du répétiteur'; + + @override + String get repeater_routingMode => 'Mode de routage'; + + @override + String get repeater_autoUseSavedPath => + 'Auto (utiliser le chemin sauvegardé)'; + + @override + String get repeater_forceFloodMode => 'Mode de submersion forcée'; + + @override + String get repeater_pathManagement => 'Gestion des chemins'; + + @override + String get repeater_refresh => 'Rafraîchir'; + + @override + String get repeater_statusRequestTimeout => + 'Demande de statut délai dépassé.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Erreur lors du chargement du statut : $error'; + } + + @override + String get repeater_systemInformation => 'Informations Système'; + + @override + String get repeater_battery => 'Batterie'; + + @override + String get repeater_clockAtLogin => 'Horloge (au démarrage)'; + + @override + String get repeater_uptime => 'Disponibilité'; + + @override + String get repeater_queueLength => 'Longueur de la file d\'attente'; + + @override + String get repeater_debugFlags => 'Marqueurs de débogage'; + + @override + String get repeater_radioStatistics => 'Statistiques Radio'; + + @override + String get repeater_lastRssi => 'Dernier RSSI'; + + @override + String get repeater_lastSnr => 'Dernier SNR'; + + @override + String get repeater_noiseFloor => 'Niveau de Bruit'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Statistiques des paquets'; + + @override + String get repeater_sent => 'Envoyé'; + + @override + String get repeater_received => 'Reçu'; + + @override + String get repeater_duplicates => 'Dupliques'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days jours ${hours}h ${minutes}m ${seconds}s'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Total : $total, Inondation : $flood, Direct : $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Total : $total, Inondation : $flood, Direct : $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Inondation : $flood, Direct : $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Total : $total'; + } + + @override + String get repeater_settingsTitle => 'Paramètres du répétiteur'; + + @override + String get repeater_basicSettings => 'Paramètres de base'; + + @override + String get repeater_repeaterName => 'Nom du répétiteur'; + + @override + String get repeater_repeaterNameHelper => 'Afficher le nom de ce répétiteur'; + + @override + String get repeater_adminPassword => 'Mot de passe Administrateur'; + + @override + String get repeater_adminPasswordHelper => 'Mot de passe d\'accès complet'; + + @override + String get repeater_guestPassword => 'Mot de passe invité'; + + @override + String get repeater_guestPasswordHelper => + 'Accès en lecture seule avec mot de passe'; + + @override + String get repeater_radioSettings => 'Paramètres Radio'; + + @override + String get repeater_frequencyMhz => 'Fréquence (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Puissance'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Bande passante'; + + @override + String get repeater_spreadingFactor => 'Facteur de répartition'; + + @override + String get repeater_codingRate => 'Taux de codage'; + + @override + String get repeater_locationSettings => 'Paramètres de localisation'; + + @override + String get repeater_latitude => 'Latitude'; + + @override + String get repeater_latitudeHelper => + 'Degrés décimaux (par exemple, 37.7749)'; + + @override + String get repeater_longitude => 'Longitude'; + + @override + String get repeater_longitudeHelper => + 'Degrés décimaux (par exemple, -122,4194)'; + + @override + String get repeater_features => 'Fonctionnalités'; + + @override + String get repeater_packetForwarding => 'Transfert de paquets'; + + @override + String get repeater_packetForwardingSubtitle => + 'Activer le répétiteur pour transmettre des paquets'; + + @override + String get repeater_guestAccess => 'Accès Invité'; + + @override + String get repeater_guestAccessSubtitle => + 'Autoriser l\'accès invité en lecture seule'; + + @override + String get repeater_privacyMode => 'Mode de confidentialité'; + + @override + String get repeater_privacyModeSubtitle => + 'Cacher le nom/l\'emplacement dans les publicités'; + + @override + String get repeater_advertisementSettings => 'Paramètres de Publicité'; + + @override + String get repeater_localAdvertInterval => 'Intervalle Publicité Locale'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes minutes'; + } + + @override + String get repeater_floodAdvertInterval => + 'Intervalle de Publicité Inondation'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours heures'; + } + + @override + String get repeater_encryptedAdvertInterval => + 'Intervalle publicitaire crypté'; + + @override + String get repeater_dangerZone => 'Zone d\'alerte'; + + @override + String get repeater_rebootRepeater => 'Redémarrer Répéteur'; + + @override + String get repeater_rebootRepeaterSubtitle => + 'Réinitialiser l\'appareil répétiteur'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Êtes-vous sûr de vouloir redémarrer ce répétiteur ?'; + + @override + String get repeater_regenerateIdentityKey => 'Ré générer la clé d\'identité'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Générer une nouvelle paire de clés publique/privée'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'Cela générera une nouvelle identité pour le répétiteur. Continuer ?'; + + @override + String get repeater_eraseFileSystem => 'Supprimer le système de fichiers'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Formater le système de fichiers du répétiteur'; + + @override + String get repeater_eraseFileSystemConfirm => + 'AVERTISSEMENT : Cela effacera toutes les données du répétiteur. Cela ne peut pas être annulé !'; + + @override + String get repeater_eraseSerialOnly => + 'Erase n\'est disponible que via la console série.'; + + @override + String repeater_commandSent(String command) { + return 'Commande envoyée : $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Erreur lors de l\'envoi de la commande : $error'; + } + + @override + String get repeater_confirm => 'Confirmer'; + + @override + String get repeater_settingsSaved => + 'Les paramètres ont été enregistrés avec succès.'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Erreur lors de la sauvegarde des paramètres : $error'; + } + + @override + String get repeater_refreshBasicSettings => + 'Rafraîchir les paramètres de base'; + + @override + String get repeater_refreshRadioSettings => 'Rafraîchir les paramètres Radio'; + + @override + String get repeater_refreshTxPower => 'Rafraîchir la tension TX'; + + @override + String get repeater_refreshLocationSettings => + 'Rafraîchir les paramètres de localisation'; + + @override + String get repeater_refreshPacketForwarding => + 'Rafraîchir le routage des paquets'; + + @override + String get repeater_refreshGuestAccess => 'Rafraîchir l\'accès invité'; + + @override + String get repeater_refreshPrivacyMode => + 'Rafraîchir le Mode Confidentialité'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Rafraîchir les Paramètres de la Publicité'; + + @override + String repeater_refreshed(String label) { + return '$label rafraîchi'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Erreur lors du rafraîchissement de $label'; + } + + @override + String get repeater_cliTitle => 'Répétiteur CLI'; + + @override + String get repeater_debugNextCommand => 'Déboguer Prochaine Commande'; + + @override + String get repeater_commandHelp => 'Aide'; + + @override + String get repeater_clearHistory => 'Effacer l\'historique'; + + @override + String get repeater_noCommandsSent => + 'Aucune commande n\'a encore été envoyée.'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Saisissez une commande ci-dessous ou utilisez les commandes rapides'; + + @override + String get repeater_enterCommandHint => 'Entrer la commande...'; + + @override + String get repeater_previousCommand => 'Commande précédente'; + + @override + String get repeater_nextCommand => 'Prochaine commande'; + + @override + String get repeater_enterCommandFirst => 'Entrez d\'abord une commande'; + + @override + String get repeater_cliCommandFrameTitle => 'Frame de commande CLI'; + + @override + String repeater_cliCommandError(String error) { + return 'Erreur : $error'; + } + + @override + String get repeater_cliQuickGetName => 'Obtenir le nom'; + + @override + String get repeater_cliQuickGetRadio => 'Obtenir la Radio'; + + @override + String get repeater_cliQuickGetTx => 'Obtenir TX'; + + @override + String get repeater_cliQuickNeighbors => 'Voisins'; + + @override + String get repeater_cliQuickVersion => 'Version'; + + @override + String get repeater_cliQuickAdvertise => 'Publier'; + + @override + String get repeater_cliQuickClock => 'Horloge'; + + @override + String get repeater_cliHelpAdvert => 'Envoie un paquet publicitaire'; + + @override + String get repeater_cliHelpReboot => + 'Redémarre l\'appareil. (Note, vous risquez d\'obtenir \'Timeout\' ce qui est normal)'; + + @override + String get repeater_cliHelpClock => + 'Affiche l\'heure actuelle par l\'horloge de chaque appareil.'; + + @override + String get repeater_cliHelpPassword => + 'Définit un nouveau mot de passe administrateur pour l\'appareil.'; + + @override + String get repeater_cliHelpVersion => + 'Affiche la version du périphérique et la date de construction du micrologiciel.'; + + @override + String get repeater_cliHelpClearStats => + 'Réinitialise divers compteurs de statistiques à zéro.'; + + @override + String get repeater_cliHelpSetAf => 'Définit le facteur de temps d\'air.'; + + @override + String get repeater_cliHelpSetTx => + 'Définit la puissance de transmission LoRa en dBm (réinitialisation requise pour appliquer).'; + + @override + String get repeater_cliHelpSetRepeat => + 'Active ou désactive le rôle du répétiteur pour ce nœud.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Serveur de pièce) Si \"activé\", alors un mot de passe vide permettra la connexion, mais ne permettra pas de publier dans la pièce. (lecture seule uniquement)'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Définit le nombre maximal de sauts pour les paquets de balayage entrants (si >= max, le paquet n\'est pas acheminé).'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Définit le seuil d\'interférence (en dB). La valeur par défaut est de 14. Définir sur 0 désactive la détection des interférences de canal.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Définit l\'intervalle pour réinitialiser le contrôleur de gain automatique. Mettez à 0 pour désactiver.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Active ou désactive la fonctionnalité « double ACKs ».'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Définit l\'intervalle du minuteur pour envoyer un paquet d\'annonce local (sans relais). Définir sur 0 pour désactiver.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Définit l\'intervalle du minuteur en heures pour envoyer un paquet d\'annonce massive. Définir sur 0 pour désactiver.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Définit/met à jour le mot de passe de l\'invité. (pour les répéteurs, les connexions d\'invités peuvent envoyer la requête \"Get Stats\")'; + + @override + String get repeater_cliHelpSetName => 'Définit le nom de la publicité.'; + + @override + String get repeater_cliHelpSetLat => + 'Définit la latitude de la carte des annonces. (degrés décimaux)'; + + @override + String get repeater_cliHelpSetLon => + 'Définit la longitude de la carte de l\'annonce. (degrés décimaux)'; + + @override + String get repeater_cliHelpSetRadio => + 'Définit complètement de nouveaux paramètres de radio et les enregistre dans les préférences. Nécessite une commande \"redémarrage\" pour les appliquer.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Paramètres (expérimental) de base pour appliquer un léger délai aux paquets reçus, en fonction de la force du signal/score. Définir sur 0 pour désactiver.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Définit un facteur multiplié par le temps de fonctionnement en mode inondation pour un paquet et avec un système de slot aléatoire, afin de retarder son envoi (pour diminuer la probabilité de collisions).'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Identique à txdelay, mais pour appliquer un délai aléatoire au transfert des paquets en mode direct.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => 'Activer/Désactiver le pont.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Définir le délai avant de renvoyer les paquets.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Choisissez si le pont retransmettra les paquets reçus ou les paquets transmis.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Définir la vitesse de communication série pour les ponts Rs232.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Définir le secret du pont pour les ponts espnow.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Définit un facteur personnalisé pour ajuster la tension de la batterie signalée (uniquement pris en charge sur certains cartes).'; + + @override + String get repeater_cliHelpTempRadio => + 'Définit des paramètres radio temporaires pour le nombre de minutes donné, puis revient aux paramètres radio d\'origine. (ne sauvegarde pas dans les préférences).'; + + @override + String get repeater_cliHelpSetPerm => + 'Modifie l’ACL. Supprime l’entrée correspondante (par préfixe de clé publique) si \"permissions\" est égal à zéro. Ajoute une nouvelle entrée si la clé publique hexadécimale a une longueur complète et n’est pas actuellement dans l’ACL. Met à jour l’entrée en fonction du préfixe de clé publique. Les bits de permission varient en fonction du rôle du firmware, mais les 2 bits inférieurs sont : 0 (Invité), 1 (Lecture seule), 2 (Lecture/écriture), 3 (Administrateur).'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Obtenir le type de pont : aucun, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => + 'Démarre l\'enregistrement des paquets dans le système de fichiers.'; + + @override + String get repeater_cliHelpLogStop => + 'Arrêter de journaliser les paquets vers le système de fichiers.'; + + @override + String get repeater_cliHelpLogErase => + 'Supprime les journaux de paquets du système de fichiers.'; + + @override + String get repeater_cliHelpNeighbors => + 'Affiche une liste d\'autres nœuds répétiteurs entendus via des publicités sans relais. Chaque ligne est id-préfixe-hexadécimal:timestamp:snr-fois-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Supprime la première entrée correspondante (par préfixe de clé publique (hexadécimal)) de la liste des voisins.'; + + @override + String get repeater_cliHelpRegion => + '(série uniquement) Liste toutes les régions définies et les autorisations de débordement actuelles.'; + + @override + String get repeater_cliHelpRegionLoad => + 'REMARQUE : il s\'agit d\'une invocation multi-commande spéciale. Chaque commande subséquente est un nom de région (indenté avec des espaces pour indiquer la hiérarchie parent, avec un minimum d\'un espace). Terminé par l\'envoi d\'une ligne vide/commande.'; + + @override + String get repeater_cliHelpRegionGet => + 'Recherche la région avec le préfixe de nom donné (ou \"\" pour l\'étendue globale). Répond avec \"-> nom-de-région (nom-parent) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Ajoute ou met à jour une définition de région avec le nom donné.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Supprime une définition de région avec le nom donné.'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Définit les autorisations de \"Flot\" pour la région donnée. (\'\' pour la portée globale/héritée)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Supprime l\'autorisation \'F\'lood\' pour la région donnée. (NOTE : à ce stade, il n\'est pas conseillé de l\'utiliser sur l\'étendue globale/héritée !! )'; + + @override + String get repeater_cliHelpRegionHome => + 'Répond avec la région \'maison\' actuelle. (Note appliquée nulle part pour l\'instant, réservée à une utilisation future)'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Définit la région \'maison\'.'; + + @override + String get repeater_cliHelpRegionSave => + 'Conserve la liste/la carte des régions dans le stockage.'; + + @override + String get repeater_cliHelpGps => + 'Affiche l’état du GPS. Lorsque le GPS est éteint, il répond uniquement « éteint », si allumé, il répond avec « allumé », l’état, la correction, le nombre de satellites.'; + + @override + String get repeater_cliHelpGpsOnOff => 'Activer/désactiver le GPS.'; + + @override + String get repeater_cliHelpGpsSync => + 'Synchronise l\'heure du nœud avec l\'horloge GPS.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Définit la position du nœud aux coordonnées GPS et enregistre les préférences.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Donne la configuration de l\'annonce de la localisation du nœud :\n- none : ne pas inclure la localisation dans les annonces\n- share : partager la localisation GPS (du SensorManager)\n- prefs : annoncer la localisation stockée dans les préférences'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Définit la configuration de l\'annonce de localisation.'; + + @override + String get repeater_commandsListTitle => 'Liste des commandes'; + + @override + String get repeater_commandsListNote => + 'NOTE : pour les diverses commandes « set »..., il existe également une commande « get »...'; + + @override + String get repeater_general => 'Général'; + + @override + String get repeater_settingsCategory => 'Paramètres'; + + @override + String get repeater_bridge => 'Pont'; + + @override + String get repeater_logging => 'Journalisation'; + + @override + String get repeater_neighborsRepeaterOnly => + 'Voisins (Uniquement répétiteur)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Gestion des régions (uniquement pour le répétiteur)'; + + @override + String get repeater_regionNote => + 'Les commandes de région ont été introduites pour gérer les définitions et les autorisations des régions.'; + + @override + String get repeater_gpsManagement => 'Gestion GPS'; + + @override + String get repeater_gpsNote => + 'La commande GPS a été introduite pour gérer les sujets liés à la localisation.'; + + @override + String get telemetry_receivedData => 'Données de télémétrie reçues'; + + @override + String get telemetry_requestTimeout => 'Demande de télémétrie expirée.'; + + @override + String telemetry_errorLoading(String error) { + return 'Erreur lors du chargement de la télémétrie : $error'; + } + + @override + String get telemetry_noData => 'Aucune donnée de télémétrie disponible.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Canal $channel'; + } + + @override + String get telemetry_batteryLabel => 'Batterie'; + + @override + String get telemetry_voltageLabel => 'Tension'; + + @override + String get telemetry_mcuTemperatureLabel => 'Température du MCU'; + + @override + String get telemetry_temperatureLabel => 'Température'; + + @override + String get telemetry_currentLabel => 'Actuellement'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Chemin de paquet'; + + @override + String get channelPath_viewMap => 'Afficher la carte'; + + @override + String get channelPath_otherObservedPaths => 'Autres chemins observés'; + + @override + String get channelPath_repeaterHops => 'Sauts du répétiteur'; + + @override + String get channelPath_noHopDetails => + 'Les détails de l\'envoi ne sont pas fournis pour ce paquet.'; + + @override + String get channelPath_messageDetails => 'Détails du message'; + + @override + String get channelPath_senderLabel => 'Expéditeur'; + + @override + String get channelPath_timeLabel => 'Temps'; + + @override + String get channelPath_repeatsLabel => 'Répétitions'; + + @override + String channelPath_pathLabel(int index) { + return 'Chemin $index'; + } + + @override + String get channelPath_observedLabel => 'Observé'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Chemin observé $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'Aucune donnée de localisation'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Inconnu'; + + @override + String get channelPath_floodPath => 'Inondation'; + + @override + String get channelPath_directPath => 'Afficher'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 de $total sauts'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed sur $total sauts'; + } + + @override + String get channelPath_mapTitle => 'Carte du chemin'; + + @override + String get channelPath_noRepeaterLocations => + 'Aucune position de répétiteur disponible pour ce chemin.'; + + @override + String channelPath_primaryPath(int index) { + return 'Chemin $index (Principal)'; + } + + @override + String get channelPath_pathLabelTitle => 'Chemin'; + + @override + String get channelPath_observedPathHeader => 'Chemin observé'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'Aucun détail de saut disponible pour ce paquet.'; + + @override + String get channelPath_unknownRepeater => 'Répéteur Inconnu'; + + @override + String get listFilter_tooltip => 'Filtrer et trier'; + + @override + String get listFilter_sortBy => 'Trier par'; + + @override + String get listFilter_latestMessages => 'Dernières messages'; + + @override + String get listFilter_heardRecently => 'Écoute récemment'; + + @override + String get listFilter_az => 'A à Z'; + + @override + String get listFilter_filters => 'Filtres'; + + @override + String get listFilter_all => 'Tout'; + + @override + String get listFilter_users => 'Utilisateurs'; + + @override + String get listFilter_repeaters => 'Répéteurs'; + + @override + String get listFilter_roomServers => 'Serveurs de pièce'; + + @override + String get listFilter_unreadOnly => 'Messages non lus seulement'; + + @override + String get listFilter_newGroup => 'Nouvelle groupe'; +} diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart new file mode 100644 index 0000000..cd2d022 --- /dev/null +++ b/lib/l10n/app_localizations_it.dart @@ -0,0 +1,2389 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Italian (`it`). +class AppLocalizationsIt extends AppLocalizations { + AppLocalizationsIt([String locale = 'it']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Contatti'; + + @override + String get nav_channels => 'Canali'; + + @override + String get nav_map => 'Mappa'; + + @override + String get common_cancel => 'Annulla'; + + @override + String get common_connect => 'Connetti'; + + @override + String get common_unknownDevice => 'Dispositivo sconosciuto'; + + @override + String get common_save => 'Salva'; + + @override + String get common_delete => 'Elimina'; + + @override + String get common_close => 'Chiudi'; + + @override + String get common_edit => 'Modifica'; + + @override + String get common_add => 'Aggiungi'; + + @override + String get common_settings => 'Impostazioni'; + + @override + String get common_disconnect => 'Disconnetti'; + + @override + String get common_connected => 'Connesso'; + + @override + String get common_disconnected => 'Disconnesso'; + + @override + String get common_create => 'Crea'; + + @override + String get common_continue => 'Continua'; + + @override + String get common_share => 'Condividi'; + + @override + String get common_copy => 'Copia'; + + @override + String get common_retry => 'Riprova'; + + @override + String get common_hide => 'Nascondi'; + + @override + String get common_remove => 'Elimina'; + + @override + String get common_enable => 'Abilita'; + + @override + String get common_disable => 'Disattivare'; + + @override + String get common_reboot => 'Riavvia'; + + @override + String get common_loading => 'Caricamento...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Scansione in corso per i dispositivi...'; + + @override + String get scanner_connecting => 'Connessione...'; + + @override + String get scanner_disconnecting => 'Disconnessione...'; + + @override + String get scanner_notConnected => 'Non connesso'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Connesso a $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Ricerca dispositivi MeshCore...'; + + @override + String get scanner_tapToScan => + 'Tocca Scansiona per trovare i dispositivi MeshCore'; + + @override + String scanner_connectionFailed(String error) { + return 'Connessione fallita: $error'; + } + + @override + String get scanner_stop => 'Interrompere'; + + @override + String get scanner_scan => 'Scansiona'; + + @override + String get device_quickSwitch => 'Passa velocemente'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Impostazioni'; + + @override + String get settings_deviceInfo => 'Informazioni Dispositivo'; + + @override + String get settings_appSettings => 'Impostazioni App'; + + @override + String get settings_appSettingsSubtitle => + 'Notifiche, messaggi e preferenze della mappa'; + + @override + String get settings_nodeSettings => 'Impostazioni Nodo'; + + @override + String get settings_nodeName => 'Nome Nodo'; + + @override + String get settings_nodeNameNotSet => 'Non impostato'; + + @override + String get settings_nodeNameHint => 'Inserisci nome nodo'; + + @override + String get settings_nodeNameUpdated => 'Nome aggiornato'; + + @override + String get settings_radioSettings => 'Impostazioni Radio'; + + @override + String get settings_radioSettingsSubtitle => + 'Frequenza, potenza, fattore di dispersione'; + + @override + String get settings_radioSettingsUpdated => 'Impostazioni radio aggiornate'; + + @override + String get settings_location => 'Posizione'; + + @override + String get settings_locationSubtitle => 'coordinate GPS'; + + @override + String get settings_locationUpdated => 'Posizione aggiornata'; + + @override + String get settings_locationBothRequired => + 'Inserire sia la latitudine che la longitudine.'; + + @override + String get settings_locationInvalid => 'Latitudine o longitudine non valida.'; + + @override + String get settings_latitude => 'Latitudine'; + + @override + String get settings_longitude => 'Longitudine'; + + @override + String get settings_privacyMode => 'Modalità Privacy'; + + @override + String get settings_privacyModeSubtitle => + 'Nascondere nome/luogo negli annunci'; + + @override + String get settings_privacyModeToggle => + 'Attiva la modalità privacy per nascondere il tuo nome e la tua posizione negli annunci.'; + + @override + String get settings_privacyModeEnabled => 'Modalità privacy abilitata'; + + @override + String get settings_privacyModeDisabled => 'Modalità privacy disabilitata'; + + @override + String get settings_actions => 'Azioni'; + + @override + String get settings_sendAdvertisement => 'Invia Annuncio'; + + @override + String get settings_sendAdvertisementSubtitle => 'Presenza trasmessa ora'; + + @override + String get settings_advertisementSent => 'Annuncio inviato'; + + @override + String get settings_syncTime => 'Tempo di sincronizzazione'; + + @override + String get settings_syncTimeSubtitle => + 'Imposta l\'orologio del dispositivo sull\'ora del telefono'; + + @override + String get settings_timeSynchronized => 'Sincronizzato nel tempo'; + + @override + String get settings_refreshContacts => 'Aggiorna Contatti'; + + @override + String get settings_refreshContactsSubtitle => + 'Ricaricare l\'elenco dei contatti dal dispositivo'; + + @override + String get settings_rebootDevice => 'Riavvia Dispositivo'; + + @override + String get settings_rebootDeviceSubtitle => + 'Riavviare il dispositivo MeshCore'; + + @override + String get settings_rebootDeviceConfirm => + 'Sei sicuro di voler riavviare il dispositivo? Sarai disconnesso.'; + + @override + String get settings_debug => 'Risoluzione dei problemi'; + + @override + String get settings_bleDebugLog => 'Log di Debug BLE'; + + @override + String get settings_bleDebugLogSubtitle => + 'Comandi, risposte e dati grezzi BLE'; + + @override + String get settings_appDebugLog => 'Log di Debug dell\'App'; + + @override + String get settings_appDebugLogSubtitle => + 'Messaggi di debug dell\'applicazione'; + + @override + String get settings_about => 'Informazioni'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => 'Progetto Open Source MeshCore 2024'; + + @override + String get settings_aboutDescription => + 'Un client Flutter open-source per i dispositivi di rete mesh LoRa Core di MeshCore.'; + + @override + String get settings_infoName => 'Nome'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'Stato'; + + @override + String get settings_infoBattery => 'Batteria'; + + @override + String get settings_infoPublicKey => 'Chiave Pubblica'; + + @override + String get settings_infoContactsCount => 'Numero contatti'; + + @override + String get settings_infoChannelCount => 'Numero Canale'; + + @override + String get settings_presets => 'Preset'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Frequenza (MHz)'; + + @override + String get settings_frequencyHelper => '300,0 - 2500,0'; + + @override + String get settings_frequencyInvalid => 'Frequenza non valida (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Larghezza di banda'; + + @override + String get settings_spreadingFactor => 'Fattore di Spettro'; + + @override + String get settings_codingRate => 'Tasso di Codifica'; + + @override + String get settings_txPower => 'TX Potenza (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Potere TX non valido (0-22 dBm)'; + + @override + String get settings_longRange => 'Lungo Raggio'; + + @override + String get settings_fastSpeed => 'Velocità Rapida'; + + @override + String settings_error(String message) { + return 'Errore: $message'; + } + + @override + String get appSettings_title => 'Impostazioni App'; + + @override + String get appSettings_appearance => 'Aspetto'; + + @override + String get appSettings_theme => 'Tema'; + + @override + String get appSettings_themeSystem => 'Impostazione predefinita del sistema'; + + @override + String get appSettings_themeLight => 'Luce'; + + @override + String get appSettings_themeDark => 'Scuro'; + + @override + String get appSettings_language => 'Lingua'; + + @override + String get appSettings_languageSystem => 'Predefinito di sistema'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Notifiche'; + + @override + String get appSettings_enableNotifications => 'Abilita Notifiche'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Ricevi notifiche per messaggi e annunci'; + + @override + String get appSettings_notificationPermissionDenied => + 'Permesso di notifica negato'; + + @override + String get appSettings_notificationsEnabled => 'Notifiche abilitate'; + + @override + String get appSettings_notificationsDisabled => 'Notifiche disattivate'; + + @override + String get appSettings_messageNotifications => 'Notifiche Messaggi'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Mostra notifica all\'arrivo di nuovi messaggi'; + + @override + String get appSettings_channelMessageNotifications => + 'Notifiche Messaggi Canale'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Mostra notifica all\'arrivo di messaggi nel canale'; + + @override + String get appSettings_advertisementNotifications => + 'Notifiche Pubblicitarie'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Mostra notifica quando vengono scoperti nuovi nodi'; + + @override + String get appSettings_messaging => 'Messaggi'; + + @override + String get appSettings_clearPathOnMaxRetry => + 'Cancella Percorso su Massimo Riprovo'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Reimposta il percorso di contatto dopo 5 tentativi di invio falliti'; + + @override + String get appSettings_pathsWillBeCleared => + 'I percorsi verranno puliti dopo 5 tentativi falliti.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'I percorsi non verranno eliminati automaticamente.'; + + @override + String get appSettings_autoRouteRotation => 'Rotazione Percorso Automatico'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Alterna tra i percorsi migliori e la modalità alluvione'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Rotazione percorso automatico abilitata'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Rotazione del percorso automatico disabilitata'; + + @override + String get appSettings_battery => 'Batteria'; + + @override + String get appSettings_batteryChemistry => 'Chimica della batteria'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Impostazione per dispositivo ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Connetti a un dispositivo per scegliere'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6-3,65V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + + @override + String get appSettings_mapDisplay => 'Visualizzazione Mappa'; + + @override + String get appSettings_showRepeaters => 'Mostra Ripetitori'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Mostra i nodi ripetitori sulla mappa'; + + @override + String get appSettings_showChatNodes => 'Mostra Nodi Chat'; + + @override + String get appSettings_showChatNodesSubtitle => + 'Mostra i nodi di chat sulla mappa'; + + @override + String get appSettings_showOtherNodes => 'Mostra altri nodi'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Mostra altri tipi di nodo sulla mappa'; + + @override + String get appSettings_timeFilter => 'Filtro Temporale'; + + @override + String get appSettings_timeFilterShowAll => 'Mostra tutti i nodi'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Mostra i nodi delle ultime $hours ore'; + } + + @override + String get appSettings_mapTimeFilter => 'Filtro Tempo Mappa'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Mostra i nodi scoperti all\'interno di:'; + + @override + String get appSettings_allTime => 'Tutto il tempo'; + + @override + String get appSettings_lastHour => 'Ultima ora'; + + @override + String get appSettings_last6Hours => 'Ultimi 6 ore'; + + @override + String get appSettings_last24Hours => 'Ultime 24 ore'; + + @override + String get appSettings_lastWeek => 'La settimana scorsa'; + + @override + String get appSettings_offlineMapCache => 'Cache Mappa Offline'; + + @override + String get appSettings_noAreaSelected => 'Nessun\'area selezionata'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Area selezionata (zoom $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Risoluzione dei problemi'; + + @override + String get appSettings_appDebugLogging => 'Registrazione Debug App'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Messaggi di debug dell\'app Log per la risoluzione dei problemi'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'Logging di debug dell\'app abilitato'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'Logging del debug dell\'app disabilitato'; + + @override + String get contacts_title => 'Contatti'; + + @override + String get contacts_noContacts => 'Nessun contatto ancora'; + + @override + String get contacts_contactsWillAppear => + 'I contatti appariranno quando i dispositivi pubblicizzano.'; + + @override + String get contacts_searchContacts => 'Cerca contatti...'; + + @override + String get contacts_noUnreadContacts => 'Nessun contatto non letto'; + + @override + String get contacts_noContactsFound => 'Nessun contatto o gruppo trovato.'; + + @override + String get contacts_deleteContact => 'Elimina Contatto'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Eliminare $contactName dai contatti?'; + } + + @override + String get contacts_manageRepeater => 'Gestisci Ripetitore'; + + @override + String get contacts_roomLogin => 'Login Camera'; + + @override + String get contacts_openChat => 'Apri Chat'; + + @override + String get contacts_editGroup => 'Modifica Gruppo'; + + @override + String get contacts_deleteGroup => 'Elimina Gruppo'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Eliminare \"$groupName\"?'; + } + + @override + String get contacts_newGroup => 'Nuovo Gruppo'; + + @override + String get contacts_groupName => 'Nome gruppo'; + + @override + String get contacts_groupNameRequired => 'Il nome del gruppo è obbligatorio.'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'Il gruppo \"$name\" esiste già.'; + } + + @override + String get contacts_filterContacts => 'Filtra i contatti...'; + + @override + String get contacts_noContactsMatchFilter => + 'Nessun contatto corrisponde al tuo filtro'; + + @override + String get contacts_noMembers => 'Nessun membro'; + + @override + String get contacts_lastSeenNow => 'Ultimo avvistamento ora'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Ultimo visto $minutes minuti fa'; + } + + @override + String get contacts_lastSeenHourAgo => 'Ultimo visto 1 ora fa'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Ultimo visto $hours ore fa'; + } + + @override + String get contacts_lastSeenDayAgo => 'Ultimo visto 1 giorno fa'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Ultimo visto $days giorni fa'; + } + + @override + String get channels_title => 'Canali'; + + @override + String get channels_noChannelsConfigured => 'Nessun canale configurato'; + + @override + String get channels_addPublicChannel => 'Aggiungi Canale Pubblico'; + + @override + String get channels_searchChannels => 'Cerca canali...'; + + @override + String get channels_noChannelsFound => 'Nessun canale trovato'; + + @override + String channels_channelIndex(int index) { + return 'Canale $index'; + } + + @override + String get channels_hashtagChannel => 'Canale hashtag'; + + @override + String get channels_public => 'Pubblico'; + + @override + String get channels_private => 'Privato'; + + @override + String get channels_publicChannel => 'Canale pubblico'; + + @override + String get channels_privateChannel => 'Canale privato'; + + @override + String get channels_editChannel => 'Modifica canale'; + + @override + String get channels_deleteChannel => 'Elimina canale'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Eliminare \"$name\"? Non può essere annullato.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Canale \"$name\" eliminato'; + } + + @override + String get channels_addChannel => 'Aggiungi Canale'; + + @override + String get channels_channelIndexLabel => 'Indice Canale'; + + @override + String get channels_channelName => 'Nome canale'; + + @override + String get channels_usePublicChannel => 'Utilizza il canale pubblico'; + + @override + String get channels_standardPublicPsk => 'PSK pubblico standard'; + + @override + String get channels_pskHex => 'PSK (Hex)'; + + @override + String get channels_generateRandomPsk => + 'Genera una chiave di permutazione casuale'; + + @override + String get channels_enterChannelName => 'Inserisci un nome per il canale'; + + @override + String get channels_pskMustBe32Hex => + 'PSK deve essere composto da 32 caratteri esadecimali.'; + + @override + String channels_channelAdded(String name) { + return 'Canale \"$name\" aggiunto'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Modifica Canale $index'; + } + + @override + String get channels_smazCompression => 'Compressione SMAZ'; + + @override + String channels_channelUpdated(String name) { + return 'Canale \"$name\" aggiornato'; + } + + @override + String get channels_publicChannelAdded => 'Canale pubblico aggiunto'; + + @override + String get channels_sortBy => 'Ordina per'; + + @override + String get channels_sortManual => 'Manuale'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => 'Ultimi messaggi'; + + @override + String get channels_sortUnread => 'Non letto'; + + @override + String get chat_noMessages => 'Nessun messaggio ancora'; + + @override + String get chat_sendMessageToStart => 'Invia un messaggio per iniziare'; + + @override + String get chat_originalMessageNotFound => 'Messaggio originale non trovato'; + + @override + String chat_replyingTo(String name) { + return 'Rispondere a $name'; + } + + @override + String chat_replyTo(String name) { + return 'Rispondi a $name'; + } + + @override + String get chat_location => 'Posizione'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Invia un messaggio a $contactName'; + } + + @override + String get chat_typeMessage => 'Digita un messaggio...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Messaggio troppo lungo (massimo $maxBytes byte).'; + } + + @override + String get chat_messageCopied => 'Messaggio copiato'; + + @override + String get chat_messageDeleted => 'Messaggio eliminato'; + + @override + String get chat_retryingMessage => 'Riprovo'; + + @override + String chat_retryCount(int current, int max) { + return 'Riprova $current/$max'; + } + + @override + String get chat_sendGif => 'Invia GIF'; + + @override + String get chat_reply => 'Rispondi'; + + @override + String get chat_addReaction => 'Aggiungi Reazione'; + + @override + String get chat_me => 'Me'; + + @override + String get emojiCategorySmileys => 'Emoji'; + + @override + String get emojiCategoryGestures => 'Gesti'; + + @override + String get emojiCategoryHearts => 'Cuori'; + + @override + String get emojiCategoryObjects => 'Oggetti'; + + @override + String get gifPicker_title => 'Scegli un GIF'; + + @override + String get gifPicker_searchHint => 'Cerca GIF...'; + + @override + String get gifPicker_poweredBy => 'Potenziato da GIPHY'; + + @override + String get gifPicker_noGifsFound => 'Nessun GIF trovato'; + + @override + String get gifPicker_failedLoad => 'Impossibile caricare i GIF'; + + @override + String get gifPicker_failedSearch => 'Impossibile trovare GIF'; + + @override + String get gifPicker_noInternet => 'Nessuna connessione internet'; + + @override + String get debugLog_appTitle => 'Log di Debug dell\'App'; + + @override + String get debugLog_bleTitle => 'Log di Debug BLE'; + + @override + String get debugLog_copyLog => 'Copia log'; + + @override + String get debugLog_clearLog => 'Cancella log'; + + @override + String get debugLog_copied => 'Log di debug copiato'; + + @override + String get debugLog_bleCopied => 'Log BLE copiato'; + + @override + String get debugLog_noEntries => 'Non ci sono ancora log di debug.'; + + @override + String get debugLog_enableInSettings => + 'Abilita il logging di debug dell\'app nelle impostazioni'; + + @override + String get debugLog_frames => 'Frame'; + + @override + String get debugLog_rawLogRx => 'Log Raw-RX'; + + @override + String get debugLog_noBleActivity => 'Nessuna attività BLE rilevata ancora.'; + + @override + String debugFrame_length(int count) { + return 'Lunghezza del Frame: $count byte'; + } + + @override + String debugFrame_command(String value) { + return 'Comando: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Messaggio di testo:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Destinazione PubChiave: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Timestamp: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Flag: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return 'Tipo di testo: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Semplice'; + + @override + String debugFrame_text(String text) { + return '- Testo: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Dumpa Esadecimale:'; + + @override + String get chat_pathManagement => 'Gestione Percorsi'; + + @override + String get chat_routingMode => 'Modalità di routing'; + + @override + String get chat_autoUseSavedPath => 'Utilizza il percorso salvato'; + + @override + String get chat_forceFloodMode => 'Modalità Inondamento Forzato'; + + @override + String get chat_recentAckPaths => 'Percorsi ACK Recenti (tocca per usare):'; + + @override + String get chat_pathHistoryFull => + 'La cronologia del percorso è piena. Rimuovi gli elementi per aggiungere nuovi.'; + + @override + String get chat_hopSingular => 'salta'; + + @override + String get chat_hopPlural => 'salta'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'salti', + one: 'salto', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'successi'; + + @override + String get chat_removePath => 'Rimuovi percorso'; + + @override + String get chat_noPathHistoryYet => + 'Non c\'è ancora una cronologia del percorso.\nInvia un messaggio per scoprire i percorsi.'; + + @override + String get chat_pathActions => 'Azioni Percorso:'; + + @override + String get chat_setCustomPath => 'Imposta Percorso Personalizzato'; + + @override + String get chat_setCustomPathSubtitle => + 'Specifica manualmente il percorso di routing'; + + @override + String get chat_clearPath => 'Cancella Percorso'; + + @override + String get chat_clearPathSubtitle => + 'Riprova la scoperta alla prossima invio'; + + @override + String get chat_pathCleared => + 'Percorso sgomberato. Il prossimo messaggio riidentifierà il percorso.'; + + @override + String get chat_floodModeSubtitle => + 'Utilizza l\'interruttore di routing nella barra delle applicazioni'; + + @override + String get chat_floodModeEnabled => + 'Modalità alluvione abilitata. Disattivala tramite l\'icona di routing nella barra in alto.'; + + @override + String get chat_fullPath => 'Percorso Completo'; + + @override + String get chat_pathDetailsNotAvailable => + 'I dettagli del percorso non sono ancora disponibili. Prova a inviare un messaggio per ricaricare.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Percorso impostato: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Salvatato localmente. Connetti per sincronizzare.'; + + @override + String get chat_pathDeviceConfirmed => 'Dispositivo confermato.'; + + @override + String get chat_pathDeviceNotConfirmed => + 'Dispositivo non confermato ancora.'; + + @override + String get chat_type => 'Digita'; + + @override + String get chat_path => 'Percorso'; + + @override + String get chat_publicKey => 'Chiave Pubblica'; + + @override + String get chat_compressOutgoingMessages => 'Comprimi messaggi in uscita'; + + @override + String get chat_floodForced => 'Inondazione (forzata)'; + + @override + String get chat_directForced => 'Riavvia (forzato)'; + + @override + String chat_hopsForced(int count) { + return '$count salti (forzati)'; + } + + @override + String get chat_floodAuto => 'Inondazione (auto)'; + + @override + String get chat_direct => 'Salva'; + + @override + String get chat_poiShared => 'Punti di Interesse Condivisi'; + + @override + String chat_unread(int count) { + return 'Non letti: $count'; + } + + @override + String get map_title => 'Mappa Nodi'; + + @override + String get map_noNodesWithLocation => 'Nessun nodo con dati di posizione'; + + @override + String get map_nodesNeedGps => + 'I nodi devono condividere le loro coordinate GPS\nper apparire sulla mappa'; + + @override + String map_nodesCount(int count) { + return 'Nodi: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Puntatori: $count'; + } + + @override + String get map_chat => 'Chat'; + + @override + String get map_repeater => 'Ripetitore'; + + @override + String get map_room => 'Stanza'; + + @override + String get map_sensor => 'Sensore'; + + @override + String get map_pinDm => 'Codice PIN (DM)'; + + @override + String get map_pinPrivate => 'Blocco (Privato)'; + + @override + String get map_pinPublic => 'Pin (Pubblico)'; + + @override + String get map_lastSeen => 'Ultimo visto'; + + @override + String get map_disconnectConfirm => + 'Sei sicuro di voler disconnetterti da questo dispositivo?'; + + @override + String get map_from => 'Da'; + + @override + String get map_source => 'Fonte'; + + @override + String get map_flags => 'Bandiere'; + + @override + String get map_shareMarkerHere => 'Condividi marcatore qui'; + + @override + String get map_pinLabel => 'Etichetta PIN'; + + @override + String get map_label => 'Etichetta'; + + @override + String get map_pointOfInterest => 'Punto di interesse'; + + @override + String get map_sendToContact => 'Invia a contatto'; + + @override + String get map_sendToChannel => 'Invia al canale'; + + @override + String get map_noChannelsAvailable => 'Nessun canale disponibile'; + + @override + String get map_publicLocationShare => 'Condividi in una posizione pubblica'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'Stai per condividere una posizione in $channelLabel. Questo canale è pubblico e chiunque abbia la PSK può vederlo.'; + } + + @override + String get map_connectToShareMarkers => + 'Connetti a un dispositivo per condividere i segnaposti'; + + @override + String get map_filterNodes => 'Filtra Nodi'; + + @override + String get map_nodeTypes => 'Tipi di Nodo'; + + @override + String get map_chatNodes => 'Nodi di Chat'; + + @override + String get map_repeaters => 'Ripetitori'; + + @override + String get map_otherNodes => 'Altri Nodi'; + + @override + String get map_keyPrefix => 'Prefisso Chiave'; + + @override + String get map_filterByKeyPrefix => 'Filtra per prefisso chiave'; + + @override + String get map_publicKeyPrefix => 'Prefisso chiave pubblica'; + + @override + String get map_markers => 'Segnaposto'; + + @override + String get map_showSharedMarkers => 'Mostra i segnaposto condivisi'; + + @override + String get map_lastSeenTime => 'Ultimo Tempo di Visualizzazione'; + + @override + String get map_sharedPin => 'Condividi PIN'; + + @override + String get map_joinRoom => 'Unisciti alla stanza'; + + @override + String get map_manageRepeater => 'Gestisci Ripetitore'; + + @override + String get mapCache_title => 'Cache Mappa Offline'; + + @override + String get mapCache_selectAreaFirst => + 'Seleziona un\'area da memorizzare nella cache per prima.'; + + @override + String get mapCache_noTilesToDownload => + 'Nessun tile da scaricare per questa area'; + + @override + String get mapCache_downloadTilesTitle => 'Scarica mattoncini'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Scarica $count tile per l\'uso offline?'; + } + + @override + String get mapCache_downloadAction => 'Scarica'; + + @override + String mapCache_cachedTiles(int count) { + return 'Cacheggiate $count tile'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Tile memorizzati $downloaded ($failed falliti)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => 'Cancella cache offline'; + + @override + String get mapCache_clearOfflineCachePrompt => + 'Eliminare tutte le tile di mappa memorizzate nella cache?'; + + @override + String get mapCache_offlineCacheCleared => 'Cache offline eliminata'; + + @override + String get mapCache_noAreaSelected => 'Nessun\'area selezionata'; + + @override + String get mapCache_cacheArea => 'Area Cache'; + + @override + String get mapCache_useCurrentView => 'Utilizza la visualizzazione corrente'; + + @override + String get mapCache_zoomRange => 'Intervallo Zoom'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Stima dei mattoni: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Scaricati $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Scarica Tessere'; + + @override + String get mapCache_clearCacheButton => 'Svuota Cache'; + + @override + String mapCache_failedDownloads(int count) { + return 'Download falliti: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Proprio ora'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes minuti fa'; + } + + @override + String time_hoursAgo(int hours) { + return '${hours}h fa'; + } + + @override + String time_daysAgo(int days) { + return '$days giorni fa'; + } + + @override + String get time_hour => 'ora'; + + @override + String get time_hours => 'ore'; + + @override + String get time_day => 'giorno'; + + @override + String get time_days => 'giorni'; + + @override + String get time_week => 'settimana'; + + @override + String get time_weeks => 'settimane'; + + @override + String get time_month => 'mese'; + + @override + String get time_months => 'mesi'; + + @override + String get time_minutes => 'minuti'; + + @override + String get time_allTime => 'Tutto il Tempo'; + + @override + String get dialog_disconnect => 'Disconnetti'; + + @override + String get dialog_disconnectConfirm => + 'Sei sicuro di voler disconnetterti da questo dispositivo?'; + + @override + String get login_repeaterLogin => 'Login Ripetitore'; + + @override + String get login_roomLogin => 'Login Camera'; + + @override + String get login_password => 'Password'; + + @override + String get login_enterPassword => 'Inserisci password'; + + @override + String get login_savePassword => 'Salva password'; + + @override + String get login_savePasswordSubtitle => + 'La password verrà memorizzata in modo sicuro su questo dispositivo.'; + + @override + String get login_repeaterDescription => + 'Inserisci la password del ripetitore per accedere alle impostazioni e allo stato.'; + + @override + String get login_roomDescription => + 'Inserisci la password della stanza per accedere alle impostazioni e allo stato.'; + + @override + String get login_routing => 'Instradamento'; + + @override + String get login_routingMode => 'Modalità di routing'; + + @override + String get login_autoUseSavedPath => 'Utilizza il percorso salvato'; + + @override + String get login_forceFloodMode => 'Modalità Inondamento Forzato'; + + @override + String get login_managePaths => 'Gestisci Percorsi'; + + @override + String get login_login => 'Accedi'; + + @override + String login_attempt(int current, int max) { + return 'Prova $current/$max'; + } + + @override + String login_failed(String error) { + return 'Accesso fallito: $error'; + } + + @override + String get common_reload => 'Ricaricare'; + + @override + String get common_clear => 'Cancella'; + + @override + String path_currentPath(String path) { + return 'Percorso corrente: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Utilizzare $count $_temp0 percorso'; + } + + @override + String get path_enterCustomPath => 'Inserisci percorso personalizzato'; + + @override + String get path_currentPathLabel => 'Percorso corrente'; + + @override + String get path_hexPrefixInstructions => + 'Inserire i prefissi esadecimali a 2 caratteri per ogni salto, separati da virgole.'; + + @override + String get path_hexPrefixExample => + 'Esempio: A1,F2,3C (ogni nodo utilizza il primo byte della sua chiave pubblica)'; + + @override + String get path_labelHexPrefixes => 'Prefisso esadecimale (percorso)'; + + @override + String get path_helperMaxHops => + 'Massimo 64 salti. Ogni prefisso è composto da 2 caratteri esadecimali (1 byte)'; + + @override + String get path_selectFromContacts => 'Seleziona da contatti:'; + + @override + String get path_noRepeatersFound => + 'Non sono stati trovati ripetitori o server di stanza.'; + + @override + String get path_customPathsRequire => + 'I percorsi personalizzati richiedono salti intermedi che possono inoltrare messaggi.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Prefissi esadecimali non validi: $prefixes'; + } + + @override + String get path_tooLong => + 'Il percorso è troppo lungo. Massimo 64 salti consentiti.'; + + @override + String get path_setPath => 'Imposta Percorso'; + + @override + String get repeater_management => 'Gestione Ripetitori'; + + @override + String get repeater_managementTools => 'Strumenti di Gestione'; + + @override + String get repeater_status => 'Stato'; + + @override + String get repeater_statusSubtitle => + 'Visualizza lo stato, le statistiche e i vicini del ripetitore'; + + @override + String get repeater_telemetry => 'Telemetry'; + + @override + String get repeater_telemetrySubtitle => + 'Visualizza i dati di telemetria dei sensori e le statistiche di sistema'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Invia comandi al ripetitore'; + + @override + String get repeater_settings => 'Impostazioni'; + + @override + String get repeater_settingsSubtitle => + 'Configura i parametri del ripetitore'; + + @override + String get repeater_statusTitle => 'Stato del Ripetitore'; + + @override + String get repeater_routingMode => 'Modalità di routing'; + + @override + String get repeater_autoUseSavedPath => 'Percorso salvato automatico'; + + @override + String get repeater_forceFloodMode => 'Modalità Inondamento Forzato'; + + @override + String get repeater_pathManagement => 'Gestione dei percorsi'; + + @override + String get repeater_refresh => 'Aggiorna'; + + @override + String get repeater_statusRequestTimeout => 'Richiesta stato scaduta.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Errore nel caricamento dello stato: $error'; + } + + @override + String get repeater_systemInformation => 'Informazioni di sistema'; + + @override + String get repeater_battery => 'Batteria'; + + @override + String get repeater_clockAtLogin => 'Orologio (all\'accesso)'; + + @override + String get repeater_uptime => 'Disponibilità'; + + @override + String get repeater_queueLength => 'Lunghezza della coda'; + + @override + String get repeater_debugFlags => 'Impostazioni Debug'; + + @override + String get repeater_radioStatistics => 'Statistiche Radio'; + + @override + String get repeater_lastRssi => 'Ultimo RSSI'; + + @override + String get repeater_lastSnr => 'Ultimo SNR'; + + @override + String get repeater_noiseFloor => 'Livello del Rumore'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Statistiche del Pacchetto'; + + @override + String get repeater_sent => 'Inviato'; + + @override + String get repeater_received => 'Ricevuto'; + + @override + String get repeater_duplicates => 'Duplicati'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days giorni ${hours}h ${minutes}m ${seconds}s'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Totale: $total, Inondazione: $flood, Diretto: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Totale: $total, Inondazione: $flood, Diretto: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Inondazione: $flood, Diretto: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Totale: $total'; + } + + @override + String get repeater_settingsTitle => 'Impostazioni Ripetitore'; + + @override + String get repeater_basicSettings => 'Impostazioni di Base'; + + @override + String get repeater_repeaterName => 'Nome Ripetitore'; + + @override + String get repeater_repeaterNameHelper => + 'Visualizza il nome di questo ripetitore'; + + @override + String get repeater_adminPassword => 'Password Amministratore'; + + @override + String get repeater_adminPasswordHelper => 'Accesso completo password'; + + @override + String get repeater_guestPassword => 'Password Ospite'; + + @override + String get repeater_guestPasswordHelper => + 'Accesso in sola lettura con password'; + + @override + String get repeater_radioSettings => 'Impostazioni Radio'; + + @override + String get repeater_frequencyMhz => 'Frequenza (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Potenza'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Larghezza di banda'; + + @override + String get repeater_spreadingFactor => 'Spreading Factor'; + + @override + String get repeater_codingRate => 'Tasso di Codifica'; + + @override + String get repeater_locationSettings => 'Impostazioni Luogo'; + + @override + String get repeater_latitude => 'Latitudine'; + + @override + String get repeater_latitudeHelper => 'Grado decimale (ad esempio, 37.7749)'; + + @override + String get repeater_longitude => 'Longitudine'; + + @override + String get repeater_longitudeHelper => + 'Grado decimale (ad esempio, -122,4194)'; + + @override + String get repeater_features => 'Caratteristiche'; + + @override + String get repeater_packetForwarding => 'Instradamento Pacchetti'; + + @override + String get repeater_packetForwardingSubtitle => + 'Abilita il ripetitore per inoltrare i pacchetti'; + + @override + String get repeater_guestAccess => 'Accesso Ospite'; + + @override + String get repeater_guestAccessSubtitle => + 'Consenti l\'accesso ospite in sola lettura'; + + @override + String get repeater_privacyMode => 'Modalità Privacy'; + + @override + String get repeater_privacyModeSubtitle => + 'Nascondere nome/luogo negli annunci'; + + @override + String get repeater_advertisementSettings => 'Impostazioni Annuncio'; + + @override + String get repeater_localAdvertInterval => 'Intervallo Pubblicità Locale'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes minuti'; + } + + @override + String get repeater_floodAdvertInterval => + 'Intervallo Pubblicità Inondazione'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours ore'; + } + + @override + String get repeater_encryptedAdvertInterval => + 'Intervallo Pubblicitario Crittografato'; + + @override + String get repeater_dangerZone => 'Zona Pericolosa'; + + @override + String get repeater_rebootRepeater => 'Riavvia Ripetitore'; + + @override + String get repeater_rebootRepeaterSubtitle => + 'Riavvia il dispositivo ripetitore'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Sei sicuro di voler riavviare questo ripetitore?'; + + @override + String get repeater_regenerateIdentityKey => 'Rigenera Chiave Identità'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Genera una nuova coppia di chiavi pubblica/privata'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'Questo genererà una nuova identità per il ripetitore. Procedere?'; + + @override + String get repeater_eraseFileSystem => 'Elimina File System'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Formatta il file system del ripetitore'; + + @override + String get repeater_eraseFileSystemConfirm => + 'ATTENZIONE: Ciò cancellerà tutti i dati sul ripetitore. Non può essere annullato!'; + + @override + String get repeater_eraseSerialOnly => + 'Elimina è disponibile solo tramite console seriale.'; + + @override + String repeater_commandSent(String command) { + return 'Comando inviato: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Errore nell\'invio del comando: $error'; + } + + @override + String get repeater_confirm => 'Conferma'; + + @override + String get repeater_settingsSaved => 'Impostazioni salvate con successo'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Errore durante il salvataggio delle impostazioni: $error'; + } + + @override + String get repeater_refreshBasicSettings => 'Aggiorna Impostazioni Base'; + + @override + String get repeater_refreshRadioSettings => 'Aggiorna le Impostazioni Radio'; + + @override + String get repeater_refreshTxPower => 'Aggiorna TX potenza'; + + @override + String get repeater_refreshLocationSettings => + 'Aggiorna le Impostazioni della Posizione'; + + @override + String get repeater_refreshPacketForwarding => + 'Aggiorna il inoltro pacchetti'; + + @override + String get repeater_refreshGuestAccess => 'Aggiorna Accesso Ospite'; + + @override + String get repeater_refreshPrivacyMode => 'Aggiorna Modalità Privacy'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Aggiorna le Impostazioni dell\'Annuncio'; + + @override + String repeater_refreshed(String label) { + return '$label aggiornato'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Errore durante il ricaricamento di $label'; + } + + @override + String get repeater_cliTitle => 'Riprova CLI'; + + @override + String get repeater_debugNextCommand => 'Riavvia Comando Prossimo'; + + @override + String get repeater_commandHelp => 'Aiuto'; + + @override + String get repeater_clearHistory => 'Cancella Cronologia'; + + @override + String get repeater_noCommandsSent => 'Nessun comando inviato ancora'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Digita un comando qui sotto o usa comandi rapidi'; + + @override + String get repeater_enterCommandHint => 'Inserisci comando...'; + + @override + String get repeater_previousCommand => 'Comando precedente'; + + @override + String get repeater_nextCommand => 'Prossimo comando'; + + @override + String get repeater_enterCommandFirst => 'Inserisci un comando prima'; + + @override + String get repeater_cliCommandFrameTitle => 'Finestra Comando CLI'; + + @override + String repeater_cliCommandError(String error) { + return 'Errore: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Ottieni Nome'; + + @override + String get repeater_cliQuickGetRadio => 'Ottieni Radio'; + + @override + String get repeater_cliQuickGetTx => 'Ottieni TX'; + + @override + String get repeater_cliQuickNeighbors => 'Vicini'; + + @override + String get repeater_cliQuickVersion => 'Versione'; + + @override + String get repeater_cliQuickAdvertise => 'Pubblicare'; + + @override + String get repeater_cliQuickClock => 'Orologio'; + + @override + String get repeater_cliHelpAdvert => 'Invia un pacchetto pubblicitario'; + + @override + String get repeater_cliHelpReboot => + 'Riavvia il dispositivo. (nota, potresti ottenere \'Timeout\' che è normale)'; + + @override + String get repeater_cliHelpClock => + 'Mostra l\'ora corrente per l\'orologio di ciascun dispositivo.'; + + @override + String get repeater_cliHelpPassword => + 'Imposta una nuova password di amministratore per il dispositivo.'; + + @override + String get repeater_cliHelpVersion => + 'Mostra la versione del dispositivo e la data di costruzione del firmware.'; + + @override + String get repeater_cliHelpClearStats => + 'Resetta vari numerosi contatori di statistiche a zero.'; + + @override + String get repeater_cliHelpSetAf => + 'Imposta il fattore di tempo di trasmissione.'; + + @override + String get repeater_cliHelpSetTx => + 'Imposta la potenza di trasmissione LoRa in dBm (riavvia per applicare).'; + + @override + String get repeater_cliHelpSetRepeat => + 'Abilita o disabilita il ruolo del ripetitore per questo nodo.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Server della stanza) Se \'on\', allora l\'accesso con una password vuota sarà consentito, ma non sarà possibile pubblicare nella stanza. (solo lettura).'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Imposta il numero massimo di salti per i pacchetti di inondazione in entrata (se >= max, il pacchetto non viene inoltrato)'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Imposta il Limite di Interferenza (in dB). Il valore predefinito è 14. Imposta su 0 per disabilitare il rilevamento delle interferenze del canale.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Imposta l\'intervallo per resettare il controllore Automatico del Guadagno. Imposta su 0 per disabilitare.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Abilita o disabilita la funzione \'double ACKs\'.'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Imposta l\'intervallo del timer in minuti per inviare un pacchetto di pubblicità locale (senza salto). Imposta su 0 per disabilitare.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Imposta l\'intervallo del timer in ore per inviare un pacchetto pubblicitario di massa. Imposta su 0 per disabilitare.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Imposta/aggiorna la password dell\'ospite. (per ripetitori, gli accessi degli ospiti possono inviare la richiesta \"Get Stats\")'; + + @override + String get repeater_cliHelpSetName => 'Imposta il nome dell\'annuncio.'; + + @override + String get repeater_cliHelpSetLat => + 'Imposta la latitudine della mappa pubblicitaria. (gradi decimali)'; + + @override + String get repeater_cliHelpSetLon => + 'Imposta la longitudine della mappa pubblicitaria. (gradi decimali)'; + + @override + String get repeater_cliHelpSetRadio => + 'Imposta completamente nuovi parametri radio e li salva nelle preferenze. Richiede un comando \"reboot\" per l\'applicazione.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Impostazioni (experimental) base (deve essere > 1 per l\'effetto) per applicare un leggero ritardo ai pacchetti ricevuti, in base alla forza del segnale/punteggio. Imposta a 0 per disabilitare.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Imposta un fattore moltiplicato con il tempo di mantenimento per un pacchetto di modalità allagamento e con un sistema di slot casuale, per ritardarne la trasmissione (per diminuire la probabilità di collisioni).'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Uguale a txdelay, ma per applicare un ritardo casuale alla inoltrata di pacchetti in modalità diretta.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => 'Abilita/Disabilita ponte.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Imposta il ritardo prima di ritrasmettere i pacchetti.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Scegliere se il ponte dovrà ritrasmettere i pacchetti ricevuti o i pacchetti trasmessi.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Imposta la velocità di trasmissione per i ponti rs232.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Imposta il segreto per i ponti espnow.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Imposta un fattore personalizzato per regolare la tensione della batteria riportata (supportato solo su schede selezionate).'; + + @override + String get repeater_cliHelpTempRadio => + 'Imposta parametri radio temporanei per il numero specificato di minuti, per poi tornare ai parametri radio originali. (non salva nelle preferenze).'; + + @override + String get repeater_cliHelpSetPerm => + 'Modifica l\'ACL. Rimuove l\'entrata corrispondente (per prefisso di pubkey) se \"permissions\" è zero. Aggiunge una nuova entrata se il pubkey-hex ha lunghezza completa e non è attualmente nell\'ACL. Aggiorna l\'entrata per corrispondenza del prefisso di pubkey. I bit di permesso variano per ogni ruolo di firmware, ma i primi 2 bit sono: 0 (Guest), 1 (solo lettura), 2 (lettura/scrittura), 3 (Admin)'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Ottiene tipo ponte nessuno, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => + 'Avvia registrazione pacchetti nel file system.'; + + @override + String get repeater_cliHelpLogStop => + 'Interrompi la registrazione dei pacchetti al file system.'; + + @override + String get repeater_cliHelpLogErase => + 'Elimina i log del pacchetto dal file system.'; + + @override + String get repeater_cliHelpNeighbors => + 'Mostra un elenco di altri nodi repeater ricevuti tramite annunci zero-hop. Ogni riga è id-prefisso-esadecimale:timestamp:snr-volte-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Rimuove la prima corrispondenza in base al prefisso (esadecimale) della pubkey, dalla lista dei vicini.'; + + @override + String get repeater_cliHelpRegion => + '(solo serie) Elenca tutte le regioni definite e le autorizzazioni di allagamento correnti.'; + + @override + String get repeater_cliHelpRegionLoad => + 'NOTA: questo è un\'invocazione multi-comando speciale. Ogni comando successivo è un nome di regione (indentato con spazi per indicare la gerarchia parentale, con almeno uno spazio). Terminata inviando una riga vuota/comando.'; + + @override + String get repeater_cliHelpRegionGet => + 'Cerca la regione con il prefisso del nome dato (o \"\" per l\'ambito globale). Risponde con \"-> nome-regione (nome-genitore) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Aggiunge o aggiorna una definizione di regione con il nome specificato.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Rimuove una definizione di regione con il dato nome. (deve corrispondere esattamente e non avere regioni figlio)'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Imposta il permesso di \'F\'lood per la regione specificata. (\'\' per lo scope globale/legacy)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Rimuove il permesso \'F\'lood per la regione specificata. (NOTA: a questo stadio non è consigliato utilizzarlo sullo scope globale/legacy!!).'; + + @override + String get repeater_cliHelpRegionHome => + 'Risposte con la regione \'home\' corrente. (Nota applicata finora, riservata per il futuro)'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Imposta la regione \'home\'.'; + + @override + String get repeater_cliHelpRegionSave => + 'Persiste l\'elenco/mappa delle regioni all\'archiviazione.'; + + @override + String get repeater_cliHelpGps => + 'Mostra lo stato del GPS. Quando il GPS è spento, risponde solo \"spento\", se è acceso risponde con \"acceso\", \"stato\", \"fix\" e numero di satelliti.'; + + @override + String get repeater_cliHelpGpsOnOff => + 'Attiva/disattiva l\'alimentazione del GPS.'; + + @override + String get repeater_cliHelpGpsSync => + 'Sincronizza l\'orario del nodo con l\'orologio GPS.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Imposta la posizione del nodo alle coordinate GPS e salva le preferenze.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Fornisce la configurazione dell\'annuncio per il nodo:\n- nessuno: non includere la posizione negli annunci\n- condividi: condividi la posizione GPS (dal SensorManager)\n- preferenze: annuncia la posizione memorizzata nelle preferenze'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Imposta la configurazione dell\'annuncio sulla posizione.'; + + @override + String get repeater_commandsListTitle => 'Elenco Comandi'; + + @override + String get repeater_commandsListNote => + 'NOTA: per i vari comandi \"set...\", esiste anche un comando \"get...\".'; + + @override + String get repeater_general => 'Generale'; + + @override + String get repeater_settingsCategory => 'Impostazioni'; + + @override + String get repeater_bridge => 'Ponte'; + + @override + String get repeater_logging => 'Registrazione'; + + @override + String get repeater_neighborsRepeaterOnly => 'Vicini (solo ripetitore)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Gestione Regione (solo Ripetitore)'; + + @override + String get repeater_regionNote => + 'Sono state introdotte le comandi di regione per gestire le definizioni e le autorizzazioni delle regioni.'; + + @override + String get repeater_gpsManagement => 'Gestione GPS'; + + @override + String get repeater_gpsNote => + 'è stata introdotta una funzione gps per gestire le tematiche relative alla posizione.'; + + @override + String get telemetry_receivedData => 'Dati Telemetria Ricevuti'; + + @override + String get telemetry_requestTimeout => 'Richiesta di telemetria scaduta.'; + + @override + String telemetry_errorLoading(String error) { + return 'Errore nel caricamento della telemetria: $error'; + } + + @override + String get telemetry_noData => 'Nessun dato di telemetria disponibile.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Canale $channel'; + } + + @override + String get telemetry_batteryLabel => 'Batteria'; + + @override + String get telemetry_voltageLabel => 'Tensione'; + + @override + String get telemetry_mcuTemperatureLabel => 'Temperatura MCU'; + + @override + String get telemetry_temperatureLabel => 'Temperatura'; + + @override + String get telemetry_currentLabel => 'Attuale'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Percorso Pacchetto'; + + @override + String get channelPath_viewMap => 'Visualizza la mappa'; + + @override + String get channelPath_otherObservedPaths => 'Altri Percorsi Osservati'; + + @override + String get channelPath_repeaterHops => 'Passaggi Ripetitore'; + + @override + String get channelPath_noHopDetails => + 'I dettagli relativi a questo pacchetto non sono forniti.'; + + @override + String get channelPath_messageDetails => 'Dettagli Messaggio'; + + @override + String get channelPath_senderLabel => 'Mittente'; + + @override + String get channelPath_timeLabel => 'Tempo'; + + @override + String get channelPath_repeatsLabel => 'Ripeti'; + + @override + String channelPath_pathLabel(int index) { + return 'Percorso $index'; + } + + @override + String get channelPath_observedLabel => 'Osservato'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Percorso osservato $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'Nessun dato di posizione'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Sconosciuto'; + + @override + String get channelPath_floodPath => 'Inondazione'; + + @override + String get channelPath_directPath => 'Salva'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 di $total salti'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed di $total salti'; + } + + @override + String get channelPath_mapTitle => 'Mappa del Percorso'; + + @override + String get channelPath_noRepeaterLocations => + 'Non sono disponibili posizioni per i ripetitori per questo percorso.'; + + @override + String channelPath_primaryPath(int index) { + return 'Percorso $index (Primario)'; + } + + @override + String get channelPath_pathLabelTitle => 'Percorso'; + + @override + String get channelPath_observedPathHeader => 'Percorso Osservato'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'Non sono disponibili i dettagli del salto per questo pacchetto.'; + + @override + String get channelPath_unknownRepeater => 'Ripetitore sconosciuto'; + + @override + String get listFilter_tooltip => 'Filtra e ordina'; + + @override + String get listFilter_sortBy => 'Ordina per'; + + @override + String get listFilter_latestMessages => 'Ultimi messaggi'; + + @override + String get listFilter_heardRecently => 'Sentito di recente'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Filtri'; + + @override + String get listFilter_all => 'Tutti'; + + @override + String get listFilter_users => 'Utenti'; + + @override + String get listFilter_repeaters => 'Ripetitori'; + + @override + String get listFilter_roomServers => 'Server della stanza'; + + @override + String get listFilter_unreadOnly => 'Solo non letto'; + + @override + String get listFilter_newGroup => 'Nuovo gruppo'; +} diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart new file mode 100644 index 0000000..3484c0a --- /dev/null +++ b/lib/l10n/app_localizations_nl.dart @@ -0,0 +1,2382 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Dutch Flemish (`nl`). +class AppLocalizationsNl extends AppLocalizations { + AppLocalizationsNl([String locale = 'nl']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Contacten'; + + @override + String get nav_channels => 'Kanaal'; + + @override + String get nav_map => 'Kaart'; + + @override + String get common_cancel => 'Annuleren'; + + @override + String get common_connect => 'Verbinden'; + + @override + String get common_unknownDevice => 'Onbekend apparaat'; + + @override + String get common_save => 'Opslaan'; + + @override + String get common_delete => 'Verwijderen'; + + @override + String get common_close => 'Sluiten'; + + @override + String get common_edit => 'Bewerk'; + + @override + String get common_add => 'Toevoegen'; + + @override + String get common_settings => 'Instellingen'; + + @override + String get common_disconnect => 'Verbinden verbreken'; + + @override + String get common_connected => 'Verbonden'; + + @override + String get common_disconnected => 'Ontkoppeld'; + + @override + String get common_create => 'Maak'; + + @override + String get common_continue => 'Doorgaan'; + + @override + String get common_share => 'Delen'; + + @override + String get common_copy => 'Kopiëren'; + + @override + String get common_retry => 'Nogmaals proberen'; + + @override + String get common_hide => 'Verbergen'; + + @override + String get common_remove => 'Verwijderen'; + + @override + String get common_enable => 'Aktivatie'; + + @override + String get common_disable => 'Uitschakelen'; + + @override + String get common_reboot => 'Herstarten'; + + @override + String get common_loading => 'Laad...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Scannen naar apparaten...'; + + @override + String get scanner_connecting => 'Verbinden...'; + + @override + String get scanner_disconnecting => 'Verbinding verbreken...'; + + @override + String get scanner_notConnected => 'Niet verbonden'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Verbonden met $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Zoeken naar MeshCore apparaten...'; + + @override + String get scanner_tapToScan => 'Tik Scan om MeshCore apparaten te vinden'; + + @override + String scanner_connectionFailed(String error) { + return 'Verbinding mislukt: $error'; + } + + @override + String get scanner_stop => 'Stoppen'; + + @override + String get scanner_scan => 'Scan'; + + @override + String get device_quickSwitch => 'Snelle overschakeling'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Instellingen'; + + @override + String get settings_deviceInfo => 'Apparateninformatie'; + + @override + String get settings_appSettings => 'App Instellingen'; + + @override + String get settings_appSettingsSubtitle => + 'Notificaties, berichten en kaartinstellingen'; + + @override + String get settings_nodeSettings => 'Node Instellingen'; + + @override + String get settings_nodeName => 'Node Naam'; + + @override + String get settings_nodeNameNotSet => 'Niet ingesteld'; + + @override + String get settings_nodeNameHint => 'Voer knooppuntnaam in'; + + @override + String get settings_nodeNameUpdated => 'Naam bijgewerkt'; + + @override + String get settings_radioSettings => 'Radio Instellingen'; + + @override + String get settings_radioSettingsSubtitle => + 'Frequentie, vermogen, spredfactor'; + + @override + String get settings_radioSettingsUpdated => 'Radio instellingen bijgewerkt'; + + @override + String get settings_location => 'Locatie'; + + @override + String get settings_locationSubtitle => 'GPS coördinaten'; + + @override + String get settings_locationUpdated => 'Locatie bijgewerkt'; + + @override + String get settings_locationBothRequired => + 'Voer zowel breedte- als lengtegraad in.'; + + @override + String get settings_locationInvalid => + 'Ongeldige breedtegraad of lengtegraad.'; + + @override + String get settings_latitude => 'Breedtegraad'; + + @override + String get settings_longitude => 'Lengtegraad'; + + @override + String get settings_privacyMode => 'Privacy Mode'; + + @override + String get settings_privacyModeSubtitle => + 'Naam/locatie verbergen in advertenties'; + + @override + String get settings_privacyModeToggle => + 'Schakel privacy modus in om je naam en locatie in advertenties te verbergen.'; + + @override + String get settings_privacyModeEnabled => 'Privacy modus is ingeschakeld'; + + @override + String get settings_privacyModeDisabled => 'Privacy modus is uitgeschakeld'; + + @override + String get settings_actions => 'Acties'; + + @override + String get settings_sendAdvertisement => 'Verzend Advertentie'; + + @override + String get settings_sendAdvertisementSubtitle => 'Nu aanwezigheid uitzenden'; + + @override + String get settings_advertisementSent => 'Advertentie verzonden'; + + @override + String get settings_syncTime => 'Synchronisatie Tijd'; + + @override + String get settings_syncTimeSubtitle => + 'Stel de apparaatklok in op de tijd van de telefoon.'; + + @override + String get settings_timeSynchronized => 'Tijdsynchronisatie'; + + @override + String get settings_refreshContacts => 'Contacten vernieuwen'; + + @override + String get settings_refreshContactsSubtitle => + 'Contactlijst opnieuw laden van het apparaat'; + + @override + String get settings_rebootDevice => 'Apparaat opnieuw opstarten'; + + @override + String get settings_rebootDeviceSubtitle => 'Herstart het MeshCore apparaat'; + + @override + String get settings_rebootDeviceConfirm => + 'Ben je er zeker van dat je het apparaat opnieuw wilt opstarten? Je wordt losgekoppeld.'; + + @override + String get settings_debug => 'Debug'; + + @override + String get settings_bleDebugLog => 'BLE Debug Log'; + + @override + String get settings_bleDebugLogSubtitle => + 'BLE commando\'s, antwoorden en ruwe data'; + + @override + String get settings_appDebugLog => 'App Debug Log'; + + @override + String get settings_appDebugLogSubtitle => 'Toepassingsdebugberichten'; + + @override + String get settings_about => 'Over'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => 'MeshCore Open Source Project 2024'; + + @override + String get settings_aboutDescription => + 'Een open-source Flutter client voor MeshCore LoRa mesh netwerkapparaten.'; + + @override + String get settings_infoName => 'Naam'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'Status'; + + @override + String get settings_infoBattery => 'Batterij'; + + @override + String get settings_infoPublicKey => 'Openbare Sleutel'; + + @override + String get settings_infoContactsCount => 'Aantal Contacten'; + + @override + String get settings_infoChannelCount => 'Kanaal Aantal'; + + @override + String get settings_presets => 'Presets'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Frequentie (MHz)'; + + @override + String get settings_frequencyHelper => '300,0 - 2500,0'; + + @override + String get settings_frequencyInvalid => 'Ongeldige frequentie (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Bandbreedte'; + + @override + String get settings_spreadingFactor => 'Spreadsnelheid'; + + @override + String get settings_codingRate => 'Codeertarief'; + + @override + String get settings_txPower => 'TX Vermogen (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Ongeldige TX-vermogen (0-22 dBm)'; + + @override + String get settings_longRange => 'Lang Bereik'; + + @override + String get settings_fastSpeed => 'Snelle Snelheid'; + + @override + String settings_error(String message) { + return 'Fout: $message'; + } + + @override + String get appSettings_title => 'App Instellingen'; + + @override + String get appSettings_appearance => 'Uiterlijk'; + + @override + String get appSettings_theme => 'Thema'; + + @override + String get appSettings_themeSystem => 'Standaardinstelling'; + + @override + String get appSettings_themeLight => 'Helder'; + + @override + String get appSettings_themeDark => 'Donker'; + + @override + String get appSettings_language => 'Taal'; + + @override + String get appSettings_languageSystem => 'Standaardinstelling'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Notificaties'; + + @override + String get appSettings_enableNotifications => 'Notificaties inschakelen'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Ontvang meldingen voor berichten en advertenties'; + + @override + String get appSettings_notificationPermissionDenied => + 'Toestemming tot notificaties geweigerd'; + + @override + String get appSettings_notificationsEnabled => + 'Notificaties zijn ingeschakeld'; + + @override + String get appSettings_notificationsDisabled => + 'Notificaties zijn uitgeschakeld'; + + @override + String get appSettings_messageNotifications => 'Berichtnotificaties'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Toon notificatie bij het ontvangen van nieuwe berichten'; + + @override + String get appSettings_channelMessageNotifications => + 'Kanaal Bericht Meldingen'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Toon notificatie bij het ontvangen van kanaalberichten'; + + @override + String get appSettings_advertisementNotifications => 'Advertentie-meldingen'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Toon notificatie wanneer nieuwe knooppunten worden ontdekt'; + + @override + String get appSettings_messaging => 'Berichten'; + + @override + String get appSettings_clearPathOnMaxRetry => 'Duidelijke Pad op Max Retry'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Reset contactpad na 5 mislukte verzendpogingen'; + + @override + String get appSettings_pathsWillBeCleared => + 'De paden worden na 5 mislukte pogingen leeggehaald.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Padoms worden niet automatisch verwijderd'; + + @override + String get appSettings_autoRouteRotation => 'Automatische Route Rotatie'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Wissel tussen de beste paden en floodmodus over.'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Automatische routeplanning rotatie ingeschakeld'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Automatische routeplanning rotatie is uitgeschakeld'; + + @override + String get appSettings_battery => 'Batterij'; + + @override + String get appSettings_batteryChemistry => 'Batterijchemie'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Instellen per apparaat ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Verbind met een apparaat om te selecteren'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6-3,65V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + + @override + String get appSettings_mapDisplay => 'Kaartweergave'; + + @override + String get appSettings_showRepeaters => 'Toon Herhalingen'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Toon herhalende knoopjes op de kaart'; + + @override + String get appSettings_showChatNodes => 'Chat Nodes tonen'; + + @override + String get appSettings_showChatNodesSubtitle => + 'Chatnodes weergeven op de kaart'; + + @override + String get appSettings_showOtherNodes => 'Toon Andere Knopen'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Toon andere knooptypes op de kaart'; + + @override + String get appSettings_timeFilter => 'Filter op tijd'; + + @override + String get appSettings_timeFilterShowAll => 'Alle knooppunten tonen'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Toon knopen van de laatste $hours uur'; + } + + @override + String get appSettings_mapTimeFilter => 'Filter tijd op kaart'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Toon knooppunten ontdekt binnen:'; + + @override + String get appSettings_allTime => 'Alle tijd'; + + @override + String get appSettings_lastHour => 'Laat uur'; + + @override + String get appSettings_last6Hours => 'laatste 6 uur'; + + @override + String get appSettings_last24Hours => 'De laatste 24 uur'; + + @override + String get appSettings_lastWeek => 'Laatste week'; + + @override + String get appSettings_offlineMapCache => 'Offline Kaarten Cache'; + + @override + String get appSettings_noAreaSelected => 'Geen gebied geselecteerd'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Geselecteerd gebied (zoom $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Debug'; + + @override + String get appSettings_appDebugLogging => 'App Debuggen Loggen'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Log app debugberichten voor probleemoplossing'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'App debug logging is ingeschakeld'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'App debug logging is uitgeschakeld'; + + @override + String get contacts_title => 'Contacten'; + + @override + String get contacts_noContacts => 'Nog geen contacten.'; + + @override + String get contacts_contactsWillAppear => + 'Contacten verschijnen wanneer apparaten zich aanbieden.'; + + @override + String get contacts_searchContacts => 'Zoek contacten...'; + + @override + String get contacts_noUnreadContacts => 'Geen ongelezen contacten'; + + @override + String get contacts_noContactsFound => 'Geen contacten of groepen gevonden.'; + + @override + String get contacts_deleteContact => 'Verwijder Contact'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Verwijder $contactName uit de contacten?'; + } + + @override + String get contacts_manageRepeater => 'Beheer Herhaling'; + + @override + String get contacts_roomLogin => 'Ruimte Inloggen'; + + @override + String get contacts_openChat => 'Open Chat'; + + @override + String get contacts_editGroup => 'Groep bewerken'; + + @override + String get contacts_deleteGroup => 'Groep verwijderen'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Verwijder $groupName?'; + } + + @override + String get contacts_newGroup => 'Nieuwe Groep'; + + @override + String get contacts_groupName => 'Groepnaam'; + + @override + String get contacts_groupNameRequired => 'De groepnaam is verplicht.'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'De groep \"$name\" bestaat al.'; + } + + @override + String get contacts_filterContacts => 'Filters contacten...'; + + @override + String get contacts_noContactsMatchFilter => + 'Geen contacten matchen met uw filter'; + + @override + String get contacts_noMembers => 'Geen leden'; + + @override + String get contacts_lastSeenNow => 'Laatste keer gezien nu'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Laast gezien $minutes minuten geleden'; + } + + @override + String get contacts_lastSeenHourAgo => 'Laast gezien 1 uur geleden'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Laast gezien $hours uur geleden'; + } + + @override + String get contacts_lastSeenDayAgo => 'Laatste bekeken 1 dag geleden'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Laast gezien $days dagen geleden'; + } + + @override + String get channels_title => 'Kanaal'; + + @override + String get channels_noChannelsConfigured => 'Geen kanalen geconfigureerd'; + + @override + String get channels_addPublicChannel => 'Maak Open Kanaal'; + + @override + String get channels_searchChannels => 'Zoek kanalen...'; + + @override + String get channels_noChannelsFound => 'Geen kanalen gevonden'; + + @override + String channels_channelIndex(int index) { + return 'Kanaal $index'; + } + + @override + String get channels_hashtagChannel => 'Hashtag kanaal'; + + @override + String get channels_public => 'Openbaar'; + + @override + String get channels_private => 'Privé'; + + @override + String get channels_publicChannel => 'Open kanaal'; + + @override + String get channels_privateChannel => 'Private kanaal'; + + @override + String get channels_editChannel => 'Kanaal bewerken'; + + @override + String get channels_deleteChannel => 'Kanaal verwijderen'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Verwijderen \"$name\"? Dit kan niet worden teruggedraaid.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Kanaal \"$name\" verwijderd'; + } + + @override + String get channels_addChannel => 'Kanaal toevoegen'; + + @override + String get channels_channelIndexLabel => 'Kanaalindex'; + + @override + String get channels_channelName => 'Kanaalnaam'; + + @override + String get channels_usePublicChannel => 'Gebruik Open Kanaal'; + + @override + String get channels_standardPublicPsk => 'Standaard open PSK'; + + @override + String get channels_pskHex => 'PSK (Hex)'; + + @override + String get channels_generateRandomPsk => 'Willekeurige PSK genereren'; + + @override + String get channels_enterChannelName => 'Voer een kanaalnaam in'; + + @override + String get channels_pskMustBe32Hex => + 'De PSK moet 32 hexadecimale tekens zijn.'; + + @override + String channels_channelAdded(String name) { + return 'Kanaal \"$name\" toegevoegd'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Bewerk Kanaal $index'; + } + + @override + String get channels_smazCompression => 'SMAZ compressie'; + + @override + String channels_channelUpdated(String name) { + return 'Kanaal \"$name\" is bijgewerkt'; + } + + @override + String get channels_publicChannelAdded => 'Open kanaal toegevoegd'; + + @override + String get channels_sortBy => 'Sorteren door'; + + @override + String get channels_sortManual => 'Handmatig'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => 'Recent berichten'; + + @override + String get channels_sortUnread => 'Ongelezen'; + + @override + String get chat_noMessages => 'Nog geen berichten.'; + + @override + String get chat_sendMessageToStart => 'Een bericht sturen om te beginnen'; + + @override + String get chat_originalMessageNotFound => 'Originele bericht niet gevonden'; + + @override + String chat_replyingTo(String name) { + return 'Reageren op $name'; + } + + @override + String chat_replyTo(String name) { + return 'Reageer op $name'; + } + + @override + String get chat_location => 'Locatie'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Verstuur een bericht naar $contactName'; + } + + @override + String get chat_typeMessage => 'Type een bericht...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Bericht is te lang (max $maxBytes bytes).'; + } + + @override + String get chat_messageCopied => 'Bericht gekopieerd'; + + @override + String get chat_messageDeleted => 'Bericht verwijderd'; + + @override + String get chat_retryingMessage => 'Poging opnieuw.'; + + @override + String chat_retryCount(int current, int max) { + return 'Poging opnieuw $current/$max'; + } + + @override + String get chat_sendGif => 'GIF verzenden'; + + @override + String get chat_reply => 'Reageren'; + + @override + String get chat_addReaction => 'Reactie toevoegen'; + + @override + String get chat_me => 'Mijn'; + + @override + String get emojiCategorySmileys => 'Emoji\'s'; + + @override + String get emojiCategoryGestures => 'Bewegingen'; + + @override + String get emojiCategoryHearts => 'Hartens'; + + @override + String get emojiCategoryObjects => 'Objecten'; + + @override + String get gifPicker_title => 'Kies een GIF'; + + @override + String get gifPicker_searchHint => 'Zoek GIFs...'; + + @override + String get gifPicker_poweredBy => 'Aangedreven door GIPHY'; + + @override + String get gifPicker_noGifsFound => 'Geen GIFs gevonden'; + + @override + String get gifPicker_failedLoad => 'GIF\'s konden niet worden geladen'; + + @override + String get gifPicker_failedSearch => 'Zoeken mislukt'; + + @override + String get gifPicker_noInternet => 'Geen internetverbinding'; + + @override + String get debugLog_appTitle => 'App Debug Log'; + + @override + String get debugLog_bleTitle => 'BLE Debug Log'; + + @override + String get debugLog_copyLog => 'Kopieer log'; + + @override + String get debugLog_clearLog => 'Log wissen'; + + @override + String get debugLog_copied => 'Debuglog gekopieerd'; + + @override + String get debugLog_bleCopied => 'BLE log gekopieerd'; + + @override + String get debugLog_noEntries => 'Nog geen debug logs beschikbaar.'; + + @override + String get debugLog_enableInSettings => + 'Schakel app debug logging in de instellingen'; + + @override + String get debugLog_frames => 'Ramen'; + + @override + String get debugLog_rawLogRx => 'Raw Log-RX'; + + @override + String get debugLog_noBleActivity => 'Geen BLE-activiteit nog.'; + + @override + String debugFrame_length(int count) { + return 'Frame Lengte: $count bytes'; + } + + @override + String debugFrame_command(String value) { + return 'Boodschap: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Bericht Frame:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Bestemming PubKey: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Tijdstempel: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Vlaggen: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Tekstdocumenttype: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Eenvoudig'; + + @override + String debugFrame_text(String text) { + return '- Tekst: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Hex Dump:'; + + @override + String get chat_pathManagement => 'Beheer van Paden'; + + @override + String get chat_routingMode => 'Routeerwijze'; + + @override + String get chat_autoUseSavedPath => 'Automatisch (gebruik opgeslagen pad)'; + + @override + String get chat_forceFloodMode => 'Dwing Overstromingsmodus'; + + @override + String get chat_recentAckPaths => 'Recente ACK Paden (tik om te gebruiken):'; + + @override + String get chat_pathHistoryFull => + 'De voorgeschiedenis is vol. Verwijder vermeldingen om er nieuwe aan toe te voegen.'; + + @override + String get chat_hopSingular => 'Hop'; + + @override + String get chat_hopPlural => 'hoppen'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'Succesvol'; + + @override + String get chat_removePath => 'Pad verwijderen'; + + @override + String get chat_noPathHistoryYet => + 'Geen geschiedenis van paden nog beschikbaar.\nVerzend een bericht om paden te ontdekken.'; + + @override + String get chat_pathActions => 'Padacties:'; + + @override + String get chat_setCustomPath => 'Stel aangepaste pad in'; + + @override + String get chat_setCustomPathSubtitle => 'Handmatig routepad specificeren'; + + @override + String get chat_clearPath => 'Duidelijke Pad'; + + @override + String get chat_clearPathSubtitle => + 'Dwing herontdekking bij volgende verzending'; + + @override + String get chat_pathCleared => + 'Pad is vrijgegeven. Volgende bericht herontdekt route.'; + + @override + String get chat_floodModeSubtitle => + 'Gebruik de route-schakelaar in de app-balk'; + + @override + String get chat_floodModeEnabled => + 'Overstromingsmodus is ingeschakeld. Schakel dit uit via het route-icoon in de app-balk.'; + + @override + String get chat_fullPath => 'Volledige Pad'; + + @override + String get chat_pathDetailsNotAvailable => + 'De paddetails zijn nog niet beschikbaar. Probeer een bericht te sturen om te vernieuwen.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Pad ingesteld: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Opgeslagen lokaal. Verbinden om te synchroniseren.'; + + @override + String get chat_pathDeviceConfirmed => 'Apparaat bevestigd.'; + + @override + String get chat_pathDeviceNotConfirmed => 'Apparaat nog niet bevestigd.'; + + @override + String get chat_type => 'Typen'; + + @override + String get chat_path => 'Pad'; + + @override + String get chat_publicKey => 'Openbare Sleutel'; + + @override + String get chat_compressOutgoingMessages => + 'Verzenden van uitgaande berichten comprimeren'; + + @override + String get chat_floodForced => 'Overstroming (gedwongen)'; + + @override + String get chat_directForced => 'Direct (gedwongen)'; + + @override + String chat_hopsForced(int count) { + return '$count sprongen (gedwongen)'; + } + + @override + String get chat_floodAuto => 'Overstroming (auto)'; + + @override + String get chat_direct => 'Direct'; + + @override + String get chat_poiShared => 'Gedeelde POI'; + + @override + String chat_unread(int count) { + return 'Nieuw: $count'; + } + + @override + String get map_title => 'Node Map'; + + @override + String get map_noNodesWithLocation => 'Geen knopen met locatiegegevens'; + + @override + String get map_nodesNeedGps => + 'Nodes moeten hun GPS-coördinaten delen\nom op de kaart te verschijnen'; + + @override + String map_nodesCount(int count) { + return 'Nodes: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Spelden: $count'; + } + + @override + String get map_chat => 'Chat'; + + @override + String get map_repeater => 'Herhaling'; + + @override + String get map_room => 'Ruimte'; + + @override + String get map_sensor => 'Sensor'; + + @override + String get map_pinDm => 'Verzenden als bericht (DM)'; + + @override + String get map_pinPrivate => 'Beveiligd (Privé)'; + + @override + String get map_pinPublic => 'Openbaar spikken'; + + @override + String get map_lastSeen => 'Laaste keer gezien'; + + @override + String get map_disconnectConfirm => + 'Ben je er zeker van dat je verbinding met dit apparaat wilt verbreken?'; + + @override + String get map_from => 'Van'; + + @override + String get map_source => 'Bron'; + + @override + String get map_flags => 'Vlaggen'; + + @override + String get map_shareMarkerHere => 'Deel marker hier'; + + @override + String get map_pinLabel => 'Label vastzetten'; + + @override + String get map_label => 'Label'; + + @override + String get map_pointOfInterest => 'Interessepunt'; + + @override + String get map_sendToContact => 'Verzenden naar contact'; + + @override + String get map_sendToChannel => 'Verzenden naar kanaal'; + + @override + String get map_noChannelsAvailable => 'Geen kanalen beschikbaar'; + + @override + String get map_publicLocationShare => 'Openbare locatie delen'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'U gaat een locatie delen in $channelLabel. Deze kanaal is openbaar en iedereen met de PSK kan het zien.'; + } + + @override + String get map_connectToShareMarkers => + 'Verbind met een apparaat om markers te delen'; + + @override + String get map_filterNodes => 'Filter Knopen'; + + @override + String get map_nodeTypes => 'Node Types'; + + @override + String get map_chatNodes => 'Chat Nodes'; + + @override + String get map_repeaters => 'Herhalingen'; + + @override + String get map_otherNodes => 'Andere knooppunten'; + + @override + String get map_keyPrefix => 'Prefix sleutel'; + + @override + String get map_filterByKeyPrefix => 'Filteren op sleutelvoorgemeld'; + + @override + String get map_publicKeyPrefix => 'Openbare sleutelvoorgemeld'; + + @override + String get map_markers => 'Markeringen'; + + @override + String get map_showSharedMarkers => 'Toon gedeelde markeringen'; + + @override + String get map_lastSeenTime => 'Laatste Bekeken Tijd'; + + @override + String get map_sharedPin => 'Gedeelde pin'; + + @override + String get map_joinRoom => 'Sluit Kamer'; + + @override + String get map_manageRepeater => 'Beheer Herhaling'; + + @override + String get mapCache_title => 'Offline Kaarten Cache'; + + @override + String get mapCache_selectAreaFirst => + 'Select een gebied om eerst in de cache op te slaan'; + + @override + String get mapCache_noTilesToDownload => + 'Geen tiles te downloaden voor dit gebied.'; + + @override + String get mapCache_downloadTilesTitle => 'Tiles downloaden'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Download $count tegels voor offline gebruik?'; + } + + @override + String get mapCache_downloadAction => 'Download'; + + @override + String mapCache_cachedTiles(int count) { + return 'Opgeslagen $count tegels'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Opgeslagen $downloaded tegels ($failed mislukt)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => 'Cache offline opschonen'; + + @override + String get mapCache_clearOfflineCachePrompt => + 'Alle gecachte kaarttiles verwijderen?'; + + @override + String get mapCache_offlineCacheCleared => 'Offline cache is leeggezet'; + + @override + String get mapCache_noAreaSelected => 'Geen gebied geselecteerd'; + + @override + String get mapCache_cacheArea => 'Cache-gebied'; + + @override + String get mapCache_useCurrentView => 'Gebruik Huidige Weergave'; + + @override + String get mapCache_zoomRange => 'Zoom Bereik'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Geschatte tegels: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Gedownload $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Tiles downloaden'; + + @override + String get mapCache_clearCacheButton => 'Cache legen'; + + @override + String mapCache_failedDownloads(int count) { + return 'Mislukte downloads: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Net nu'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes minuten geleden'; + } + + @override + String time_hoursAgo(int hours) { + return '$hours uur geleden'; + } + + @override + String time_daysAgo(int days) { + return '$days dagen geleden'; + } + + @override + String get time_hour => 'uur'; + + @override + String get time_hours => 'uren'; + + @override + String get time_day => 'dag'; + + @override + String get time_days => 'dagen'; + + @override + String get time_week => 'week'; + + @override + String get time_weeks => 'weken'; + + @override + String get time_month => 'maand'; + + @override + String get time_months => 'maanden'; + + @override + String get time_minutes => 'minuten'; + + @override + String get time_allTime => 'Alle tijd'; + + @override + String get dialog_disconnect => 'Verbinden verbreken'; + + @override + String get dialog_disconnectConfirm => + 'Ben je er zeker van dat je verbinding met dit apparaat wilt verbreken?'; + + @override + String get login_repeaterLogin => 'Herhaalders Inloggen'; + + @override + String get login_roomLogin => 'Ruimte Inloggen'; + + @override + String get login_password => 'Wachtwoord'; + + @override + String get login_enterPassword => 'Wachtwoord invoeren'; + + @override + String get login_savePassword => 'Wachtwoord opslaan'; + + @override + String get login_savePasswordSubtitle => + 'Het wachtwoord wordt veilig op dit apparaat opgeslagen.'; + + @override + String get login_repeaterDescription => + 'Voer het wachtwoord van de herhaling in om instellingen en status te openen.'; + + @override + String get login_roomDescription => + 'Voer het wachtwoord van de kamer in om toegang te krijgen tot instellingen en status.'; + + @override + String get login_routing => 'Routing'; + + @override + String get login_routingMode => 'Routeerwijze'; + + @override + String get login_autoUseSavedPath => 'Automatisch (gebruik opgeslagen pad)'; + + @override + String get login_forceFloodMode => 'Dwing Overstromingsmodus'; + + @override + String get login_managePaths => 'Padbeheer'; + + @override + String get login_login => 'Inloggen'; + + @override + String login_attempt(int current, int max) { + return 'Poging $current/$max'; + } + + @override + String login_failed(String error) { + return 'Inloggen mislukt: $error'; + } + + @override + String get common_reload => 'Opnieuw laden'; + + @override + String get common_clear => 'Schoonmaken'; + + @override + String path_currentPath(String path) { + return 'Huidige pad: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Gebruik $count $_temp0 pad'; + } + + @override + String get path_enterCustomPath => 'Voer aangepaste pad in'; + + @override + String get path_currentPathLabel => 'Huidige pad'; + + @override + String get path_hexPrefixInstructions => + 'Voer 2-letter hex-voorgiffen voor elke hop in, gescheiden door komma\'s.'; + + @override + String get path_hexPrefixExample => + 'Voorbeeld: A1,F2,3C (elke node gebruikt het eerste byte van zijn openbare sleutel)'; + + @override + String get path_labelHexPrefixes => 'Pad (hex-voorkeursletters)'; + + @override + String get path_helperMaxHops => + 'Maximaal 64 sprongen. Elke prefix is 2 hexadecimale tekens (1 byte)'; + + @override + String get path_selectFromContacts => 'Of select contacten:'; + + @override + String get path_noRepeatersFound => + 'Geen herhalingen of zaalservers gevonden.'; + + @override + String get path_customPathsRequire => + 'Aangepaste paden vereisen tussentse overstappen die berichten kunnen doorgeven.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Ongeldige hex-voorkeursletters: $prefixes'; + } + + @override + String get path_tooLong => + 'Pad is te lang. Maximaal 64 sprongen zijn toegestaan.'; + + @override + String get path_setPath => 'Stel Pad in'; + + @override + String get repeater_management => 'Beheer Herhalingen'; + + @override + String get repeater_managementTools => 'Beheerinstrumenten'; + + @override + String get repeater_status => 'Status'; + + @override + String get repeater_statusSubtitle => + 'Status, statistieken en buren bekijken'; + + @override + String get repeater_telemetry => 'Telemetry'; + + @override + String get repeater_telemetrySubtitle => + 'Bekijk telemetrie van sensoren en systeemgegevens'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Verzend commando\'s naar de herhaaldere'; + + @override + String get repeater_settings => 'Instellingen'; + + @override + String get repeater_settingsSubtitle => 'Configureer repeaterparameters'; + + @override + String get repeater_statusTitle => 'Status herhalen'; + + @override + String get repeater_routingMode => 'Routeerwijze'; + + @override + String get repeater_autoUseSavedPath => + 'Automatisch (gebruik opgeslagen pad)'; + + @override + String get repeater_forceFloodMode => 'Dwing Overloopmodus'; + + @override + String get repeater_pathManagement => 'Beheer van paden'; + + @override + String get repeater_refresh => 'Vernieuwen'; + + @override + String get repeater_statusRequestTimeout => 'Statusverzoek is uitgevallen.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Fout bij het laden van de status: $error'; + } + + @override + String get repeater_systemInformation => 'Systeem Informatie'; + + @override + String get repeater_battery => 'Batterij'; + + @override + String get repeater_clockAtLogin => 'Tijd (bij aanmelden)'; + + @override + String get repeater_uptime => 'Beschikbaarheid'; + + @override + String get repeater_queueLength => 'Wachttijd'; + + @override + String get repeater_debugFlags => 'Debug Flags'; + + @override + String get repeater_radioStatistics => 'Radio Statistieken'; + + @override + String get repeater_lastRssi => 'Laatste RSSI'; + + @override + String get repeater_lastSnr => 'Laatste SNR'; + + @override + String get repeater_noiseFloor => 'Ruishoordniveau'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Pakket Statistieken'; + + @override + String get repeater_sent => 'Verzonden'; + + @override + String get repeater_received => 'Ontvangen'; + + @override + String get repeater_duplicates => 'Dubbele'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days dagen $hours uur $minutes minuten $seconds seconden'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Totaal: $total, Overstroming: $flood, Direct: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Totaal: $total, Overstroming: $flood, Direct: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Overstroming: $flood, Direct: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Totaal: $total'; + } + + @override + String get repeater_settingsTitle => 'Herstelinstellingen'; + + @override + String get repeater_basicSettings => 'Basisinstellingen'; + + @override + String get repeater_repeaterName => 'Herhaalnaam'; + + @override + String get repeater_repeaterNameHelper => 'Weergave naam voor deze herhaling'; + + @override + String get repeater_adminPassword => 'Admin wachtwoord'; + + @override + String get repeater_adminPasswordHelper => 'Volledige toegangspaswoord'; + + @override + String get repeater_guestPassword => 'Wachtwoord Gast'; + + @override + String get repeater_guestPasswordHelper => 'Leesbeheer wachtwoord'; + + @override + String get repeater_radioSettings => 'Radio Instellingen'; + + @override + String get repeater_frequencyMhz => 'Frequentie (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Power'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Bandbreedte'; + + @override + String get repeater_spreadingFactor => 'Spreadsnelheid'; + + @override + String get repeater_codingRate => 'Codeertarief'; + + @override + String get repeater_locationSettings => 'Locatie Instellingen'; + + @override + String get repeater_latitude => 'Breedtegraad'; + + @override + String get repeater_latitudeHelper => 'Graadseconden (bijv. 37.7749)'; + + @override + String get repeater_longitude => 'Lengtegraad'; + + @override + String get repeater_longitudeHelper => 'Graadseconden (bijv. -122.4194)'; + + @override + String get repeater_features => 'Kenmerken'; + + @override + String get repeater_packetForwarding => 'Pakketdoorstrooming'; + + @override + String get repeater_packetForwardingSubtitle => + 'Herstel activeren om pakketten door te sturen'; + + @override + String get repeater_guestAccess => 'Toegang voor Gasten'; + + @override + String get repeater_guestAccessSubtitle => + 'Toegestane leesbeheer toegang voor gasten.'; + + @override + String get repeater_privacyMode => 'Privacy Mode'; + + @override + String get repeater_privacyModeSubtitle => + 'Naam/locatie verbergen in advertenties'; + + @override + String get repeater_advertisementSettings => 'Advertentie Instellingen'; + + @override + String get repeater_localAdvertInterval => 'Lokale Advertentie Interval'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes minuten'; + } + + @override + String get repeater_floodAdvertInterval => + 'Advertentie Interval bij overstroming'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours uur'; + } + + @override + String get repeater_encryptedAdvertInterval => + 'Versleutelde Advertentie Interval'; + + @override + String get repeater_dangerZone => 'Gevaarzone'; + + @override + String get repeater_rebootRepeater => 'Herstart Herhaalder'; + + @override + String get repeater_rebootRepeaterSubtitle => + 'De herstart van het herhalerapparaat'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Ben je er zeker van dat je deze repeater opnieuw wilt opstarten?'; + + @override + String get repeater_regenerateIdentityKey => + 'Identiteit sleutel opnieuw genereren'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Nieuwe publieke/private sleutelpaar genereren'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'Dit genereert een nieuwe identiteit voor de herhaling. Doorgaan?'; + + @override + String get repeater_eraseFileSystem => 'Verwijder Besturingssysteem'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Formateer het herhalende bestandsysteem'; + + @override + String get repeater_eraseFileSystemConfirm => + 'WAARSCHUWING: Dit zal alle gegevens op de herhaling wissen. Dit kan niet worden teruggedraaid!'; + + @override + String get repeater_eraseSerialOnly => + 'Verwijderen is alleen beschikbaar via de seriële console.'; + + @override + String repeater_commandSent(String command) { + return 'Commando verzonden: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Fout bij het verzenden van de opdracht: $error'; + } + + @override + String get repeater_confirm => 'Bevestigen'; + + @override + String get repeater_settingsSaved => 'Instellingen succesvol opgeslagen'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Fout bij het opslaan van de instellingen: $error'; + } + + @override + String get repeater_refreshBasicSettings => 'Basisinstellingen vernieuwen'; + + @override + String get repeater_refreshRadioSettings => + 'Radiozenders Instellingen Bijwerken'; + + @override + String get repeater_refreshTxPower => 'Nieuw laden TX-vermogen'; + + @override + String get repeater_refreshLocationSettings => + 'Instellingen Locatie Vernieuwen'; + + @override + String get repeater_refreshPacketForwarding => + 'Vernieuwen Pakket Doorversturing'; + + @override + String get repeater_refreshGuestAccess => 'Toegang Gast Vernieuwen'; + + @override + String get repeater_refreshPrivacyMode => 'Privacy Mode vernieuwen'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Instellingen Advertentie Bijwerken'; + + @override + String repeater_refreshed(String label) { + return '$label is vernieuwd'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Fout bij het vernieuwen van $label'; + } + + @override + String get repeater_cliTitle => 'Herhaling CLI'; + + @override + String get repeater_debugNextCommand => 'Debug Volgende Commando'; + + @override + String get repeater_commandHelp => 'Help'; + + @override + String get repeater_clearHistory => 'Verwijder Geschiedenis'; + + @override + String get repeater_noCommandsSent => 'Geen commando\'s verzonden nog.'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Typ een opdracht hieronder of gebruik snelle commando\'s'; + + @override + String get repeater_enterCommandHint => 'Voer bevel in...'; + + @override + String get repeater_previousCommand => 'Vorige opdracht'; + + @override + String get repeater_nextCommand => 'Volgende opdracht'; + + @override + String get repeater_enterCommandFirst => 'Voer eerst een commando in'; + + @override + String get repeater_cliCommandFrameTitle => 'CLI Commando Frame'; + + @override + String repeater_cliCommandError(String error) { + return 'Fout: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Haal Naam op'; + + @override + String get repeater_cliQuickGetRadio => 'Radio ontvangen'; + + @override + String get repeater_cliQuickGetTx => 'Krijg TX'; + + @override + String get repeater_cliQuickNeighbors => 'Buren'; + + @override + String get repeater_cliQuickVersion => 'Versie'; + + @override + String get repeater_cliQuickAdvertise => 'Advertenties'; + + @override + String get repeater_cliQuickClock => 'Tijd'; + + @override + String get repeater_cliHelpAdvert => 'Verstuurt een advertentiepakket'; + + @override + String get repeater_cliHelpReboot => + 'Herstart het apparaat. (let op, je krijgt mogelijk een \'Timeout\', wat normaal is)'; + + @override + String get repeater_cliHelpClock => + 'Toont de huidige tijd per apparaat\'s klok.'; + + @override + String get repeater_cliHelpPassword => + 'Stelt een nieuw beheerderswachtwoord in voor het apparaat.'; + + @override + String get repeater_cliHelpVersion => + 'Toont de apparaatversie en firmware-bouwdatum.'; + + @override + String get repeater_cliHelpClearStats => + 'Reset verschillende statistiek-tellers naar nul.'; + + @override + String get repeater_cliHelpSetAf => 'Stelt de luchtvaartfactor in.'; + + @override + String get repeater_cliHelpSetTx => + 'Stelt LoRa zendvermogen in dBm. (om te wijzigen)'; + + @override + String get repeater_cliHelpSetRepeat => + 'Activeert of deactiveert de herhalerrol voor dit knoop.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Kamervisie) Als \'aan\', dan wordt inloggen met een blanco wachtwoord toegestaan, maar kan niet naar de kamervisie Posten. (alleen lezen mogelijk).'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Stelt het maximale aantal hops van een inkomend overlastpakket in (indien >= max, wordt het pakket niet doorgestuurd)'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Stelt de Interferentiewaarde (in dB) in. Standaardwaarde is 14. Stel in op 0 om het detecteren van kanaalinterferentie uit te schakelen.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Stelt het interval in om de Auto Gain Controller te resetten. Stel in op 0 om dit uit te schakelen.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Activeert of deactiveert de functie \'dubbele ACKs\'.'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Stelt het timerinterval in minuten in om een lokale (zero-hop) advertentiepakket te versturen. Stel in op 0 om uit te schakelen.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Stelt het timerinterval in uren in om een overstromingsadvertentiepakket te versturen. Stel in op 0 om dit uit te schakelen.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Stelt/past de gastenwacht aan of wijzigt deze. (voor herstelcontacten kunnen gastelogins de \"Get Stats\" verzoek verzenden)'; + + @override + String get repeater_cliHelpSetName => 'Stelt de advertentietitel in.'; + + @override + String get repeater_cliHelpSetLat => + 'Stelt de breedtegraad van de advertentiekaart in. (graadrijssysteem)'; + + @override + String get repeater_cliHelpSetLon => + 'Stelt de lengtegraad van de advertentiekaart in. (graadrijtjes)'; + + @override + String get repeater_cliHelpSetRadio => + 'Stelt volledig nieuwe radio parameters in en slaat deze op in de instellingen. Vereist een \"reboot\" commando om toe te passen.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Sets (experimenteel) basis (moet > 1 zijn voor effect) om een lichte vertraging toe te passen op ontvangen pakketten, gebaseerd op signaalsterkte/score. Stel op 0 om uit te schakelen.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Stelt een factor in werking die wordt vermenigvuldigd met de tijd op lucht voor een flood-mode pakket en met een willekeurig slot systeem, om de verzending ervan te vertragen (om de kans op botsingen te verminderen).'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Vergelijkbaar met txdelay, maar voor het toepassen van een willekeurige vertraging bij het doorsturen van pakketten in directe modus.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => + 'Poort inschakelen/uitschakelen.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Verzend vertraging instellen voor pakketten.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Kies of de brug ontvangen pakketten of verzonden pakketten opnieuw moet versturen.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Stel de seriële link baudrate in voor rs232 bruggen.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Stel bridge-geheim in voor espnow bridges.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Stelt een aangepaste factor in om de gerapporteerde batterijspanning aan te passen (alleen ondersteund op selecte borden).'; + + @override + String get repeater_cliHelpTempRadio => + 'Stelt tijdelijke radio parameters in voor het opgegeven aantal minuten, en keert daarna terug naar de originele radio parameters. (wordt niet opgeslagen in de voorkeuren).'; + + @override + String get repeater_cliHelpSetPerm => + 'Wijzigt de ACL. Verwijder de overeenkomstige entry (door pubkey prefix) als \"permissions\" 0 is. Voeg een nieuwe entry toe als pubkey-hex volledig is en niet momenteel in de ACL staat. Update de entry door matching pubkey prefix. Toestemming bits variëren per firmware rol, maar de onderste 2 bits zijn: 0 (Gast), 1 (Alleen lezen), 2 (Lezen/schrijven), 3 (Admin)'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Ontvang brugtype: geen, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => + 'Start pakketlogging naar het bestandssysteem.'; + + @override + String get repeater_cliHelpLogStop => + 'Stoppen met het loggen van pakketten naar het bestandssysteem.'; + + @override + String get repeater_cliHelpLogErase => + 'Verwijdert de pakketlogs uit het bestandssysteem.'; + + @override + String get repeater_cliHelpNeighbors => + 'Toont een lijst met andere repeater nodes die via nul-hop advertenties zijn gehoord. Elke regel is id-prefix-hex:timestamp:snr-times-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Verwijdert de eerste overeenkomende vermelding (via pubkey prefix (hex)) uit de lijst van buren.'; + + @override + String get repeater_cliHelpRegion => + '(reeks alleen) Lijst alle gedefinieerde regio\'s en huidige overstromingsrechten.'; + + @override + String get repeater_cliHelpRegionLoad => + 'LET OP: dit is een speciale multi-command aanroep. Elke volgende opdracht is een regiortaak (uitgelijnd met spaties om de ouderhiërarchie aan te duiden, met minimaal één spatie). Beëindigd door een lege regel/opdracht te sturen.'; + + @override + String get repeater_cliHelpRegionGet => + 'Zoekt naar regio met gegeven naam voorvoegsel (of \"\" voor de globale scope). Antwoordt met \"-> regio-naam (ouder-naam) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Voegt of wijzigt een regio-definitie met de gegeven naam.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Verwijdert een regio-definitie met de gegeven naam. (moet exact overeenkomen en geen kindregio\'s hebben)'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Stelt de \'F\'lood-toestemming in voor de opgegeven regio. (\'\' voor de globale/oude scope)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Verwijdert de \'F\'lood-toestemming voor de gegeven regio. (LET OP: op dit moment niet aanbevolen om dit op de globale/oude scope te gebruiken!!)'; + + @override + String get repeater_cliHelpRegionHome => + 'Antwoorden met de huidige \'thuis\'-regio. (Op dit moment nergens toegepast, gereserveerd voor toekomstig gebruik)'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Stelt de \'thuis\'-regio in.'; + + @override + String get repeater_cliHelpRegionSave => + 'Bewaar de lijst/kaart van de regio\'s naar de opslag.'; + + @override + String get repeater_cliHelpGps => + 'Geeft de status van de GPS. Wanneer de GPS uit staat, antwoordt het alleen met \"uit\", als het aan staat, antwoordt het met \"aan\", status, fix, sat count.'; + + @override + String get repeater_cliHelpGpsOnOff => 'Schakel de GPS-standby aan/uit.'; + + @override + String get repeater_cliHelpGpsSync => 'Synchroniseer knooptime met GPS-klok.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Stel de positie van het knoop vast naar GPS-coördinaten en sla de voorkeuren op.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Geeft de locatie advertentieconfiguratie van de node:\n- none: locatie niet in advertenties opnemen\n- share: gps locatie delen (van SensorManager)\n- prefs: locatie adverteren die in de voorkeuren is opgeslagen'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Stelt advertentie locatie configuratie in.'; + + @override + String get repeater_commandsListTitle => 'Commandenlijst'; + + @override + String get repeater_commandsListNote => + 'LET OP: voor de verschillende \"set ...\" commando\'s is er ook een \"get ...\" commando.'; + + @override + String get repeater_general => 'Algemeen'; + + @override + String get repeater_settingsCategory => 'Instellingen'; + + @override + String get repeater_bridge => 'Bruggen'; + + @override + String get repeater_logging => 'Logging'; + + @override + String get repeater_neighborsRepeaterOnly => 'Buren (Alleen herhaald)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Regiobeheer (Alleen voor Repeater)'; + + @override + String get repeater_regionNote => + 'Regio-commando\'s zijn geïntroduceerd om regio-definities en permissies te beheren.'; + + @override + String get repeater_gpsManagement => 'Beheer GPS'; + + @override + String get repeater_gpsNote => + 'De GPS-commando is geïntroduceerd om locatiegerelateerde onderwerpen te beheren.'; + + @override + String get telemetry_receivedData => 'Ontvangen Telemetriedata'; + + @override + String get telemetry_requestTimeout => 'Telemetryverzoek is uitgevallen.'; + + @override + String telemetry_errorLoading(String error) { + return 'Fout bij het laden van de telemetrie: $error'; + } + + @override + String get telemetry_noData => 'Geen telemetriedata beschikbaar.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Kanaal $channel'; + } + + @override + String get telemetry_batteryLabel => 'Batterij'; + + @override + String get telemetry_voltageLabel => 'Spanning'; + + @override + String get telemetry_mcuTemperatureLabel => 'MCU Temperatuur'; + + @override + String get telemetry_temperatureLabel => 'Temperatuur'; + + @override + String get telemetry_currentLabel => 'Huidig'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Pakketpad'; + + @override + String get channelPath_viewMap => 'Kaart bekijken'; + + @override + String get channelPath_otherObservedPaths => 'Overige Waargenomen Paden'; + + @override + String get channelPath_repeaterHops => 'Herhalingstapjes'; + + @override + String get channelPath_noHopDetails => + 'De details van de pakket zijn niet verstrekt.'; + + @override + String get channelPath_messageDetails => 'Details Bericht'; + + @override + String get channelPath_senderLabel => 'Afzender'; + + @override + String get channelPath_timeLabel => 'Tijd'; + + @override + String get channelPath_repeatsLabel => 'Herhalen'; + + @override + String channelPath_pathLabel(int index) { + return 'Pad $index'; + } + + @override + String get channelPath_observedLabel => 'Waargenomen'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Waargenomen pad $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'Geen locatiegegevens'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Onbekend'; + + @override + String get channelPath_floodPath => 'Overstroming'; + + @override + String get channelPath_directPath => 'Direct'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 van $total sprongen'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed van $total sprongen'; + } + + @override + String get channelPath_mapTitle => 'Padkaart'; + + @override + String get channelPath_noRepeaterLocations => + 'Geen herhaler locaties beschikbaar voor deze route.'; + + @override + String channelPath_primaryPath(int index) { + return 'Pad $index (Hoofdtype)'; + } + + @override + String get channelPath_pathLabelTitle => 'Pad'; + + @override + String get channelPath_observedPathHeader => 'Waargenomen Pad'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'Geen details beschikbaar voor dit pakket.'; + + @override + String get channelPath_unknownRepeater => 'Onbekend Herhaalaar'; + + @override + String get listFilter_tooltip => 'Filteren en sorteren'; + + @override + String get listFilter_sortBy => 'Sorteren door'; + + @override + String get listFilter_latestMessages => 'Recente berichten'; + + @override + String get listFilter_heardRecently => 'Hoor je onlangs'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Filters'; + + @override + String get listFilter_all => 'Alles'; + + @override + String get listFilter_users => 'Gebruikers'; + + @override + String get listFilter_repeaters => 'Herhalingen'; + + @override + String get listFilter_roomServers => 'Kamervirtualisatie'; + + @override + String get listFilter_unreadOnly => 'Alleen ongelezen'; + + @override + String get listFilter_newGroup => 'Nieuwe groep'; +} diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart new file mode 100644 index 0000000..180d8e2 --- /dev/null +++ b/lib/l10n/app_localizations_pl.dart @@ -0,0 +1,2387 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Polish (`pl`). +class AppLocalizationsPl extends AppLocalizations { + AppLocalizationsPl([String locale = 'pl']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Kontakty'; + + @override + String get nav_channels => 'Kanały'; + + @override + String get nav_map => 'Mapa'; + + @override + String get common_cancel => 'Anuluj'; + + @override + String get common_connect => 'Połącz'; + + @override + String get common_unknownDevice => 'Nieznane urządzenie'; + + @override + String get common_save => 'Zapisz'; + + @override + String get common_delete => 'Usuń'; + + @override + String get common_close => 'Zamknąć'; + + @override + String get common_edit => 'Edytuj'; + + @override + String get common_add => 'Dodaj'; + + @override + String get common_settings => 'Ustawienia'; + + @override + String get common_disconnect => 'Odłącz'; + + @override + String get common_connected => 'Połączono'; + + @override + String get common_disconnected => 'Odłączony'; + + @override + String get common_create => 'Utwórz'; + + @override + String get common_continue => 'Kontynuuj'; + + @override + String get common_share => 'Udostępnij'; + + @override + String get common_copy => 'Kopiuj'; + + @override + String get common_retry => 'Spróbować'; + + @override + String get common_hide => 'Ukryj'; + + @override + String get common_remove => 'Usuń'; + + @override + String get common_enable => 'Włącz'; + + @override + String get common_disable => 'Wyłączyć'; + + @override + String get common_reboot => 'Zrestartować'; + + @override + String get common_loading => 'Ładowanie...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Skanowanie urządzeń...'; + + @override + String get scanner_connecting => 'Łączenie...'; + + @override + String get scanner_disconnecting => 'Odłączanie...'; + + @override + String get scanner_notConnected => 'Niepołączony'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Połączono z $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Wyszukiwanie urządzeń MeshCore...'; + + @override + String get scanner_tapToScan => + 'Naciśnij Skan, aby znaleźć urządzenia MeshCore'; + + @override + String scanner_connectionFailed(String error) { + return 'Połączenie nieudane: $error'; + } + + @override + String get scanner_stop => 'Zatrzymaj'; + + @override + String get scanner_scan => 'Przeskanuj'; + + @override + String get device_quickSwitch => 'Szybka zmiana'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Ustawienia'; + + @override + String get settings_deviceInfo => 'Informacje o urządzeniu'; + + @override + String get settings_appSettings => 'Ustawienia aplikacji'; + + @override + String get settings_appSettingsSubtitle => + 'Powiadomienia, wiadomości i preferencje mapy'; + + @override + String get settings_nodeSettings => 'Ustawienia węzła'; + + @override + String get settings_nodeName => 'Nazwa węzła'; + + @override + String get settings_nodeNameNotSet => 'Nie ustawione'; + + @override + String get settings_nodeNameHint => 'Wprowadź nazwę węzła'; + + @override + String get settings_nodeNameUpdated => 'Imię zaktualizowane'; + + @override + String get settings_radioSettings => 'Ustawienia radia'; + + @override + String get settings_radioSettingsSubtitle => + 'Częstotliwość, moc, współczynnik rozpraszania'; + + @override + String get settings_radioSettingsUpdated => + 'Ustawienia radia zostały zaktualizowane'; + + @override + String get settings_location => 'Lokalizacja'; + + @override + String get settings_locationSubtitle => 'Koordynaty GPS'; + + @override + String get settings_locationUpdated => 'Lokalizacja zaktualizowana'; + + @override + String get settings_locationBothRequired => + 'Wprowadź zarówno szerokość, jak i długość geograficzną.'; + + @override + String get settings_locationInvalid => + 'Nieprawidłowa szerokość geograficzna lub długość geograficzna.'; + + @override + String get settings_latitude => 'Szerokość'; + + @override + String get settings_longitude => 'Długość'; + + @override + String get settings_privacyMode => 'Tryb Prywatny'; + + @override + String get settings_privacyModeSubtitle => + 'Ukryj imię/lokalizację w reklamach'; + + @override + String get settings_privacyModeToggle => + 'Włącz tryb prywatności, aby ukryć swoje imię i lokalizację w reklamach.'; + + @override + String get settings_privacyModeEnabled => 'Tryb prywatności włączony'; + + @override + String get settings_privacyModeDisabled => 'Tryb prywatności wyłączony'; + + @override + String get settings_actions => 'Działania'; + + @override + String get settings_sendAdvertisement => 'Wyślij Reklamę'; + + @override + String get settings_sendAdvertisementSubtitle => + 'Obecność transmisji jest teraz'; + + @override + String get settings_advertisementSent => 'Reklama wysłana'; + + @override + String get settings_syncTime => 'Czas synchronizacji'; + + @override + String get settings_syncTimeSubtitle => + 'Ustaw zegar urządzenia na czas telefonu.'; + + @override + String get settings_timeSynchronized => 'Synchronizacja czasu'; + + @override + String get settings_refreshContacts => 'Odśwież Kontakty'; + + @override + String get settings_refreshContactsSubtitle => + 'Odśwież listę kontaktów z urządzenia'; + + @override + String get settings_rebootDevice => 'Zrestartuj Urządzenie'; + + @override + String get settings_rebootDeviceSubtitle => 'Zrestartuj urządzenie MeshCore'; + + @override + String get settings_rebootDeviceConfirm => + 'Czy na pewno chcesz zrestartować urządzenie? Będziesz odłączony.'; + + @override + String get settings_debug => 'Debug'; + + @override + String get settings_bleDebugLog => 'Log błędów BLE'; + + @override + String get settings_bleDebugLogSubtitle => + 'Polecenia BLE, odpowiedzi i surowe dane'; + + @override + String get settings_appDebugLog => 'Log Wykonywania Aplikacji'; + + @override + String get settings_appDebugLogSubtitle => 'Komunikaty debugowania aplikacji'; + + @override + String get settings_about => 'O mnie'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => 'Projekt MeshCore Open Source 2026'; + + @override + String get settings_aboutDescription => + 'Otwarty kod źródłowy klient Flutter dla urządzeń do sieci mesh LoRa MeshCore.'; + + @override + String get settings_infoName => 'Imię'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'Status'; + + @override + String get settings_infoBattery => 'Bateria'; + + @override + String get settings_infoPublicKey => 'Klucz Publiczny'; + + @override + String get settings_infoContactsCount => 'Liczba kontaktów'; + + @override + String get settings_infoChannelCount => 'Liczba kanałów'; + + @override + String get settings_presets => 'Preset'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Częstotliwość (MHz)'; + + @override + String get settings_frequencyHelper => '300,0 - 2500,0'; + + @override + String get settings_frequencyInvalid => + 'Nieprawidłowa częstotliwość (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Przepustowość'; + + @override + String get settings_spreadingFactor => 'Rozkład Czynnika'; + + @override + String get settings_codingRate => 'Stawka Kodowania'; + + @override + String get settings_txPower => 'TX Moc (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Nieprawidłowa moc TX (0-22 dBm)'; + + @override + String get settings_longRange => 'Długi zasięg'; + + @override + String get settings_fastSpeed => 'Szybka prędkość'; + + @override + String settings_error(String message) { + return 'Błąd: $message'; + } + + @override + String get appSettings_title => 'Ustawienia aplikacji'; + + @override + String get appSettings_appearance => 'Wygląd'; + + @override + String get appSettings_theme => 'Motyw'; + + @override + String get appSettings_themeSystem => 'Domyślne ustawienia systemu'; + + @override + String get appSettings_themeLight => 'Jasne'; + + @override + String get appSettings_themeDark => 'Ciemny'; + + @override + String get appSettings_language => 'Język'; + + @override + String get appSettings_languageSystem => 'Domyślny systemowy'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Powiadomienia'; + + @override + String get appSettings_enableNotifications => 'Włącz Powiadomienia'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Otrzymuj powiadomienia o wiadomościach i reklamach.'; + + @override + String get appSettings_notificationPermissionDenied => + 'Odmowa zezwolenia na powiadomienia'; + + @override + String get appSettings_notificationsEnabled => 'Powiadomienia włączone'; + + @override + String get appSettings_notificationsDisabled => 'Powiadomienia wyłączone'; + + @override + String get appSettings_messageNotifications => + 'Powiadomienia o wiadomościach'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Pokaż powiadomienie przy otrzymywaniu nowych wiadomości'; + + @override + String get appSettings_channelMessageNotifications => + 'Powiadomienia o Wiadomościach na Kanałach'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Pokaż powiadomienie przy odbieraniu wiadomości z kanału'; + + @override + String get appSettings_advertisementNotifications => + 'Powiadomienia Reklamowe'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Wyświetl powiadomienie, gdy zostaną odkryte nowe węzły.'; + + @override + String get appSettings_messaging => 'Wiadomości'; + + @override + String get appSettings_clearPathOnMaxRetry => + 'Wyczyść Ścieżkę na Maksymalnej Próbie'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Resetuj ścieżkę kontaktu po 5 nieudanych próbach wysłania'; + + @override + String get appSettings_pathsWillBeCleared => + 'Droga będzie wyczyszczona po 5 nieudanych próbach.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Droga nie zostanie automatycznie wyczyszczona.'; + + @override + String get appSettings_autoRouteRotation => 'Automatyczne Rotowanie Trasy'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Przełączaj się między najlepszymi ścieżkami a trybem zalewowym.'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Automatyczne obracanie tras włączone'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Automatyczne obracanie tras wyłączone'; + + @override + String get appSettings_battery => 'Bateria'; + + @override + String get appSettings_batteryChemistry => 'Chemia Baterii'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Ustawione na urządzenie ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Połącz się z urządzeniem, aby wybrać'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6-3,65 V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + + @override + String get appSettings_mapDisplay => 'Wyświetlanie mapy'; + + @override + String get appSettings_showRepeaters => 'Pokaż Powtórniki'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Wyświetl węzły powtarzające się na mapie'; + + @override + String get appSettings_showChatNodes => 'Pokaż Węzły Rozmowy'; + + @override + String get appSettings_showChatNodesSubtitle => + 'Wyświetl węzły czatu na mapie'; + + @override + String get appSettings_showOtherNodes => 'Pokaż inne węzły'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Wyświetl inne typy węzłów na mapie'; + + @override + String get appSettings_timeFilter => 'Filtrowanie Czasu'; + + @override + String get appSettings_timeFilterShowAll => 'Pokaż wszystkie węzły'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Pokaż węzły z ostatnich $hours godzin'; + } + + @override + String get appSettings_mapTimeFilter => 'Filtrowanie Czasu Mapy'; + + @override + String get appSettings_showNodesDiscoveredWithin => 'Pokaż węzły odkryte w:'; + + @override + String get appSettings_allTime => 'Wszystko czasowo'; + + @override + String get appSettings_lastHour => 'Ostatnia godzina'; + + @override + String get appSettings_last6Hours => 'Ostatnie 6 godzin'; + + @override + String get appSettings_last24Hours => 'Ostatnie 24 godziny'; + + @override + String get appSettings_lastWeek => 'Tydzień temu'; + + @override + String get appSettings_offlineMapCache => 'Bufor Map Offline'; + + @override + String get appSettings_noAreaSelected => 'Nie zaznaczono żadnej powierzchni.'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Wybrany obszar (skala $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Debug'; + + @override + String get appSettings_appDebugLogging => 'Logowanie Debugowania Aplikacji'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Loguj wiadomości debugowania aplikacji w celu rozwiązywania problemów.'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'Zdebugowanie aplikacji włączone'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'Zasubskrybowane logi debugowania aplikacji wyłączone.'; + + @override + String get contacts_title => 'Kontakty'; + + @override + String get contacts_noContacts => 'Brak jeszcze kontaktów.'; + + @override + String get contacts_contactsWillAppear => + 'Kontakty będą wyświetlane, gdy urządzenia reklamują się.'; + + @override + String get contacts_searchContacts => 'Wyszukaj kontakty...'; + + @override + String get contacts_noUnreadContacts => 'Brak nieprzeczytanych kontaktów'; + + @override + String get contacts_noContactsFound => + 'Brak znalezionych kontaktów ani grup.'; + + @override + String get contacts_deleteContact => 'Usuń Kontakt'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Usuń $contactName z kontaktów?'; + } + + @override + String get contacts_manageRepeater => 'Zarządzaj Powtórzami'; + + @override + String get contacts_roomLogin => 'Logowanie do pokoju'; + + @override + String get contacts_openChat => 'Otwórz czat'; + + @override + String get contacts_editGroup => 'Edytuj Grupę'; + + @override + String get contacts_deleteGroup => 'Usuń Grupę'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Usuń \"$groupName\"?'; + } + + @override + String get contacts_newGroup => 'Nowa Grupa'; + + @override + String get contacts_groupName => 'Nazwa grupy'; + + @override + String get contacts_groupNameRequired => 'Nazwa grupy jest wymagana'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'Grupa \"$name\" już istnieje'; + } + + @override + String get contacts_filterContacts => 'Filtruj kontakty...'; + + @override + String get contacts_noContactsMatchFilter => + 'Brak pasujących kontaktów do Twojego filtra'; + + @override + String get contacts_noMembers => 'Brak członków'; + + @override + String get contacts_lastSeenNow => 'Ostatnie połączenie'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Ostatnie połączenie $minutes min temu'; + } + + @override + String get contacts_lastSeenHourAgo => 'Ostatni raz widziany 1 godzinę temu'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Ostatnie połączenie $hours godzin temu'; + } + + @override + String get contacts_lastSeenDayAgo => 'Ostatni raz widziany 1 dzień temu'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Ostatnie połączenie $days dni temu'; + } + + @override + String get channels_title => 'Kanały'; + + @override + String get channels_noChannelsConfigured => 'Brak skonfigurowanych kanałów'; + + @override + String get channels_addPublicChannel => 'Dodaj kanał publiczny'; + + @override + String get channels_searchChannels => 'Wyszukaj kanały...'; + + @override + String get channels_noChannelsFound => 'Brak znalezionych kanałów'; + + @override + String channels_channelIndex(int index) { + return 'Kanał $index'; + } + + @override + String get channels_hashtagChannel => 'Kanał z hashtagami'; + + @override + String get channels_public => 'Publiczny'; + + @override + String get channels_private => 'Prywatne'; + + @override + String get channels_publicChannel => 'Kanał publiczny'; + + @override + String get channels_privateChannel => 'Prywatny kanał'; + + @override + String get channels_editChannel => 'Edytuj kanał'; + + @override + String get channels_deleteChannel => 'Usuń kanał'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Usuń \"$name\"? Nie można tego cofnąć.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Kanał \"$name\" usunięto'; + } + + @override + String get channels_addChannel => 'Dodaj Kanał'; + + @override + String get channels_channelIndexLabel => 'Indeks kanału'; + + @override + String get channels_channelName => 'Nazwa kanału'; + + @override + String get channels_usePublicChannel => 'Użyj kanału publicznego'; + + @override + String get channels_standardPublicPsk => 'Standard public PSK'; + + @override + String get channels_pskHex => 'PSK (Hex)'; + + @override + String get channels_generateRandomPsk => 'Wygeneruj losowy klucz PSK'; + + @override + String get channels_enterChannelName => 'Proszę podać nazwę kanału.'; + + @override + String get channels_pskMustBe32Hex => 'PSK musi mieć 32 znaki szesnastkowe.'; + + @override + String channels_channelAdded(String name) { + return 'Kanał \"$name\" dodany'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Edytuj Kanał $index'; + } + + @override + String get channels_smazCompression => 'Kompresja SMAZ'; + + @override + String channels_channelUpdated(String name) { + return 'Kanał \"$name\" został zaktualizowany'; + } + + @override + String get channels_publicChannelAdded => 'Kanał publiczny dodany'; + + @override + String get channels_sortBy => 'Sortuj po'; + + @override + String get channels_sortManual => 'Ręczna'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => 'Najnowsze wiadomości'; + + @override + String get channels_sortUnread => 'Niezgłoszone'; + + @override + String get chat_noMessages => 'Brak jeszcze wiadomości'; + + @override + String get chat_sendMessageToStart => 'Wyślij wiadomość, aby rozpocząć.'; + + @override + String get chat_originalMessageNotFound => + 'Błąd: Nie znaleziono oryginalnego komunikatu'; + + @override + String chat_replyingTo(String name) { + return 'Odpowiadanie na $name'; + } + + @override + String chat_replyTo(String name) { + return 'Odpowiedz $name'; + } + + @override + String get chat_location => 'Lokalizacja'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Wyślij wiadomość do $contactName'; + } + + @override + String get chat_typeMessage => 'Wpisz wiadomość...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Wiadomość jest za długa (maksymalnie $maxBytes bajtów).'; + } + + @override + String get chat_messageCopied => 'Wiadomość skopiowana'; + + @override + String get chat_messageDeleted => 'Wiadomość usunięta'; + + @override + String get chat_retryingMessage => 'Próba ponowienia'; + + @override + String chat_retryCount(int current, int max) { + return 'Spróbuj $current/$max'; + } + + @override + String get chat_sendGif => 'Wyślij GIF'; + + @override + String get chat_reply => 'Odpowiedz'; + + @override + String get chat_addReaction => 'Dodaj Reakcję'; + + @override + String get chat_me => 'Ja'; + + @override + String get emojiCategorySmileys => 'Emoji'; + + @override + String get emojiCategoryGestures => 'Gestikulacje'; + + @override + String get emojiCategoryHearts => 'Serce'; + + @override + String get emojiCategoryObjects => 'Obiekty'; + + @override + String get gifPicker_title => 'Wybierz GIF'; + + @override + String get gifPicker_searchHint => 'Wyszukaj GIF-y...'; + + @override + String get gifPicker_poweredBy => 'Zasilane przez GIPHY'; + + @override + String get gifPicker_noGifsFound => 'Nie znaleziono GIF-ów'; + + @override + String get gifPicker_failedLoad => 'Nie udało się załadować GIF-ów'; + + @override + String get gifPicker_failedSearch => 'Nie udało się znaleźć GIF-ów'; + + @override + String get gifPicker_noInternet => 'Brak połączenia internetowego'; + + @override + String get debugLog_appTitle => 'Log Wykonywania Aplikacji'; + + @override + String get debugLog_bleTitle => 'Log błędów BLE'; + + @override + String get debugLog_copyLog => 'Kopiuj log'; + + @override + String get debugLog_clearLog => 'Wyczyść dziennik'; + + @override + String get debugLog_copied => 'Skopiowano dziennik debugowania'; + + @override + String get debugLog_bleCopied => 'Skopiowany log BLE'; + + @override + String get debugLog_noEntries => 'Nie ma jeszcze żadnych logów debugowania.'; + + @override + String get debugLog_enableInSettings => + 'Włącz logowanie debugowania aplikacji w ustawieniach'; + + @override + String get debugLog_frames => 'Ramy'; + + @override + String get debugLog_rawLogRx => 'Surowe Log-RX'; + + @override + String get debugLog_noBleActivity => 'Brak aktywności BLE jeszcze.'; + + @override + String debugFrame_length(int count) { + return 'Długość ramy: $count bajtów'; + } + + @override + String debugFrame_command(String value) { + return 'Polecenie: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Wiadomość tekstowa:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Oznaczenie PubKey: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Timestamp: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Flagi: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Typ tekstu: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Proste'; + + @override + String debugFrame_text(String text) { + return '- Tekst: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Wyjście SzESZCZNULNE:'; + + @override + String get chat_pathManagement => 'Zarządzanie ścieżkami'; + + @override + String get chat_routingMode => 'Tryb routingu'; + + @override + String get chat_autoUseSavedPath => 'Automatyczne (użyj zapisanej ścieżki)'; + + @override + String get chat_forceFloodMode => 'Wymusz Tryb Powodowany'; + + @override + String get chat_recentAckPaths => + 'Ostatnie ścieżki ACK (naciśnij, aby użyć):'; + + @override + String get chat_pathHistoryFull => + 'Historia ścieżek jest pełna. Usuń wpisy, aby dodać nowe.'; + + @override + String get chat_hopSingular => 'Skacz'; + + @override + String get chat_hopPlural => 'skoczkowie'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'Sukcesy'; + + @override + String get chat_removePath => 'Usuń ścieżkę'; + + @override + String get chat_noPathHistoryYet => + 'Brak jeszcze historii ścieżek.\nWyślij wiadomość, aby odkryć ścieżki.'; + + @override + String get chat_pathActions => 'Działania ścieżki:'; + + @override + String get chat_setCustomPath => 'Ustaw Ścieżkę Dostosowaną'; + + @override + String get chat_setCustomPathSubtitle => 'Ręcznie określ trasę.'; + + @override + String get chat_clearPath => 'Wyczyść Ścieżkę'; + + @override + String get chat_clearPathSubtitle => + 'Zmusz do ponownej identyfikacji przy następnym wysłaniu'; + + @override + String get chat_pathCleared => + 'Ścieżka oczyszczona. Kolejne powiadomienie odnajdzie trasę.'; + + @override + String get chat_floodModeSubtitle => + 'Użyj przełącznika routingu w pasku narzędzi.'; + + @override + String get chat_floodModeEnabled => + 'Tryb powodziowy włączony. Włącz ponownie za pomocą ikony routingu w pasku narzędzi.'; + + @override + String get chat_fullPath => 'Pełna ścieżka'; + + @override + String get chat_pathDetailsNotAvailable => + 'Szczegóły ścieżki jeszcze niedostępne. Spróbuj wysłać wiadomość, aby odświeżyć.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Ścieżka ustawiona: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Zapisano lokalnie. Połącz się, aby zsynchronizować.'; + + @override + String get chat_pathDeviceConfirmed => 'Urządzenie potwierdzone.'; + + @override + String get chat_pathDeviceNotConfirmed => + 'Urządzenie nie zostało jeszcze potwierdzone.'; + + @override + String get chat_type => 'Wprowadź'; + + @override + String get chat_path => 'Ścieżka'; + + @override + String get chat_publicKey => 'Klucz Publiczny'; + + @override + String get chat_compressOutgoingMessages => 'Kompresuj wychodzące wiadomości'; + + @override + String get chat_floodForced => 'Powodowana Powódź'; + + @override + String get chat_directForced => 'Bezpośrednio (wymuszono)'; + + @override + String chat_hopsForced(int count) { + return '$count skoków (wymuszonych)'; + } + + @override + String get chat_floodAuto => 'Powodzie (automatyczne)'; + + @override + String get chat_direct => 'Bezpośrednio'; + + @override + String get chat_poiShared => 'Wspólny POI'; + + @override + String chat_unread(int count) { + return 'Niezgłoszone: $count'; + } + + @override + String get map_title => 'Mapa węzłów'; + + @override + String get map_noNodesWithLocation => 'Brak węzłów z danymi lokalizacyjnymi'; + + @override + String get map_nodesNeedGps => + 'Węzły muszą udostępniać swoje współrzędne GPS,\naby pojawić się na mapie.'; + + @override + String map_nodesCount(int count) { + return 'Węzły: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Pinki: $count'; + } + + @override + String get map_chat => 'Rozmowa'; + + @override + String get map_repeater => 'Powtórzacz'; + + @override + String get map_room => 'Pokój'; + + @override + String get map_sensor => 'Czujnik'; + + @override + String get map_pinDm => 'Zablokuj (DM)'; + + @override + String get map_pinPrivate => 'Zablokuj (Prywatnie)'; + + @override + String get map_pinPublic => 'Oznacz jako publiczne'; + + @override + String get map_lastSeen => 'Ostatni raz widziany'; + + @override + String get map_disconnectConfirm => + 'Czy na pewno chcesz się odłączyć od tego urządzenia?'; + + @override + String get map_from => 'Od'; + + @override + String get map_source => 'Źródło'; + + @override + String get map_flags => 'Flagi'; + + @override + String get map_shareMarkerHere => 'Udostępnij znacznik tutaj'; + + @override + String get map_pinLabel => 'Oznacz etykietę'; + + @override + String get map_label => 'Etykieta'; + + @override + String get map_pointOfInterest => 'Punkt zainteresowań'; + + @override + String get map_sendToContact => 'Wyślij do kontaktu'; + + @override + String get map_sendToChannel => 'Wyślij do kanału'; + + @override + String get map_noChannelsAvailable => 'Brak dostępnych kanałów'; + + @override + String get map_publicLocationShare => 'Udostępnij lokalizację publicznie'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'Wkrótce udostępnisz lokalizację w $channelLabel. Ten kanał jest publiczny i każdy z PSK może go zobaczyć.'; + } + + @override + String get map_connectToShareMarkers => + 'Połącz się z urządzeniem, aby udostępniać znacznik.'; + + @override + String get map_filterNodes => 'Filtruj Węzły'; + + @override + String get map_nodeTypes => 'Typy węzłów'; + + @override + String get map_chatNodes => 'Węzły czatu'; + + @override + String get map_repeaters => 'Powtarzacze'; + + @override + String get map_otherNodes => 'Inne węzły'; + + @override + String get map_keyPrefix => 'Prefiks klucza'; + + @override + String get map_filterByKeyPrefix => 'Filtruj po prefiksie klucza'; + + @override + String get map_publicKeyPrefix => 'Przewód klucza publicznego'; + + @override + String get map_markers => 'Oznaczarki'; + + @override + String get map_showSharedMarkers => 'Pokaż współdzielone znaki.'; + + @override + String get map_lastSeenTime => 'Ostatni raz widiany'; + + @override + String get map_sharedPin => 'Podzielony PIN'; + + @override + String get map_joinRoom => 'Dołącz do pokoju'; + + @override + String get map_manageRepeater => 'Zarządzaj Powtórzami'; + + @override + String get mapCache_title => 'Bufor Map Offline'; + + @override + String get mapCache_selectAreaFirst => + 'Wybierz obszar do wstępnego pobrania.'; + + @override + String get mapCache_noTilesToDownload => + 'Brak dostępnych płytek do pobrania dla tego obszaru.'; + + @override + String get mapCache_downloadTilesTitle => 'Pobierz płytki'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Pobierz $count płytek do użytku offline?'; + } + + @override + String get mapCache_downloadAction => 'Pobierz'; + + @override + String mapCache_cachedTiles(int count) { + return 'Pamiętanych $count płytek'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Pamiętane $downloaded płytki ($failed nieudane)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => + 'Wyczyść pamięć podręczną offline'; + + @override + String get mapCache_clearOfflineCachePrompt => + 'Usuń wszystkie tymczasowe kafelki mapy?'; + + @override + String get mapCache_offlineCacheCleared => + 'Pamięć podręczna offline została wyczyszczona'; + + @override + String get mapCache_noAreaSelected => 'Nie zaznaczono żadnej powierzchni.'; + + @override + String get mapCache_cacheArea => 'Obszar pamięci podręcznej'; + + @override + String get mapCache_useCurrentView => 'Użyj aktualnego widoku'; + + @override + String get mapCache_zoomRange => 'Zakres powiększenia'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Szacunkowa liczba płytek: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Pobrano $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Pobierz Paski'; + + @override + String get mapCache_clearCacheButton => 'Wyczyść pamięć podręczną'; + + @override + String mapCache_failedDownloads(int count) { + return 'Nieudane pobrania: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Właśnie teraz'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes minut temu'; + } + + @override + String time_hoursAgo(int hours) { + return '${hours}h temu'; + } + + @override + String time_daysAgo(int days) { + return '$days dni temu'; + } + + @override + String get time_hour => 'godzina'; + + @override + String get time_hours => 'godziny'; + + @override + String get time_day => 'dzień'; + + @override + String get time_days => 'dni'; + + @override + String get time_week => 'tydzień'; + + @override + String get time_weeks => 'tygodnie'; + + @override + String get time_month => 'miesiąc'; + + @override + String get time_months => 'miesiace'; + + @override + String get time_minutes => 'minuty'; + + @override + String get time_allTime => 'Wszystko czasowo'; + + @override + String get dialog_disconnect => 'Odłącz'; + + @override + String get dialog_disconnectConfirm => + 'Czy na pewno chcesz się odłączyć od tego urządzenia?'; + + @override + String get login_repeaterLogin => 'Powtórz Logowanie'; + + @override + String get login_roomLogin => 'Logowanie do pokoju'; + + @override + String get login_password => 'Hasło'; + + @override + String get login_enterPassword => 'Wprowadź hasło'; + + @override + String get login_savePassword => 'Zapisz hasło'; + + @override + String get login_savePasswordSubtitle => + 'Hasło będzie bezpiecznie przechowywane na tym urządzeniu.'; + + @override + String get login_repeaterDescription => + 'Wprowadź hasło do powtarzacza, aby uzyskać dostęp do ustawień i statusu.'; + + @override + String get login_roomDescription => + 'Wprowadź hasło do pokoju, aby uzyskać dostęp do ustawień i statusu.'; + + @override + String get login_routing => 'Przekierowanie'; + + @override + String get login_routingMode => 'Tryb routingu'; + + @override + String get login_autoUseSavedPath => 'Automatycznie (użyj zapisanej ścieżki)'; + + @override + String get login_forceFloodMode => 'Wymusz Tryb Powodowany'; + + @override + String get login_managePaths => 'Zarządzaj Ścieżkami'; + + @override + String get login_login => 'Zaloguj się'; + + @override + String login_attempt(int current, int max) { + return 'Próba $current/$max'; + } + + @override + String login_failed(String error) { + return 'Zalogowanie się nie powiodło: $error'; + } + + @override + String get common_reload => 'Ponownie załadować'; + + @override + String get common_clear => 'Wyczyść'; + + @override + String path_currentPath(String path) { + return 'Aktualny ścieżka: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Użyj ścieżki $count $_temp0.'; + } + + @override + String get path_enterCustomPath => 'Wprowadź własną ścieżkę'; + + @override + String get path_currentPathLabel => 'Aktualny ścieżka'; + + @override + String get path_hexPrefixInstructions => + 'Wprowadź 2-znakowe prefiksy szesnastkowe dla każdego skoku, oddzielone przecinkami.'; + + @override + String get path_hexPrefixExample => + 'A1,F2,3C (każedy węzeł używa pierwszego bajtu swojego klucza publicznego)'; + + @override + String get path_labelHexPrefixes => 'Ścieżka (przesunięcia bitowe)'; + + @override + String get path_helperMaxHops => + 'Maksymalnie 64 skoki. Każda prefiks ma 2 znaki szesnastkowe (1 bajt).'; + + @override + String get path_selectFromContacts => 'Albo wybierz z kontaktów:'; + + @override + String get path_noRepeatersFound => + 'Nie znaleziono repeaterów ani serwerów pokoi.'; + + @override + String get path_customPathsRequire => + 'Dostosowane ścieżki wymagają pośrednich skoków, które mogą przekazywać wiadomości.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Nieprawidłowe prefiksy szesnastkowe: $prefixes'; + } + + @override + String get path_tooLong => + 'Ścieżka jest zbyt długa. Dozwolonych skoków wynosi 64.'; + + @override + String get path_setPath => 'Ustaw Ścieżkę'; + + @override + String get repeater_management => 'Zarządzanie Powtórzami'; + + @override + String get repeater_managementTools => 'Narzędzia Zarządzania'; + + @override + String get repeater_status => 'Status'; + + @override + String get repeater_statusSubtitle => + 'Wyświetl status powtarzacza, statystyki i sąsiadów.'; + + @override + String get repeater_telemetry => 'Telemetry'; + + @override + String get repeater_telemetrySubtitle => + 'Wyświetl dane telemetryczne z czujników i statystyki systemu'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Wyślij polecenia do powielacza'; + + @override + String get repeater_settings => 'Ustawienia'; + + @override + String get repeater_settingsSubtitle => 'Skonfiguruj parametry powtarzacza'; + + @override + String get repeater_statusTitle => 'Status powtarzacza'; + + @override + String get repeater_routingMode => 'Tryb routingu'; + + @override + String get repeater_autoUseSavedPath => + 'Automatycznie (użyj zapisanej ścieżki)'; + + @override + String get repeater_forceFloodMode => 'Wymusz Tryb Powodowany'; + + @override + String get repeater_pathManagement => 'Zarządzanie ścieżkami'; + + @override + String get repeater_refresh => 'Odśwież'; + + @override + String get repeater_statusRequestTimeout => 'Życzenie statusu timed out.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Błąd podczas ładowania statusu: $error'; + } + + @override + String get repeater_systemInformation => 'Informacje o systemie'; + + @override + String get repeater_battery => 'Bateria'; + + @override + String get repeater_clockAtLogin => 'Godzina (przy logowaniu)'; + + @override + String get repeater_uptime => 'Dostępność'; + + @override + String get repeater_queueLength => 'Długość kolejki'; + + @override + String get repeater_debugFlags => 'Opcje debugowania'; + + @override + String get repeater_radioStatistics => 'Statystyki Radia'; + + @override + String get repeater_lastRssi => 'Ostatni RSSI'; + + @override + String get repeater_lastSnr => 'Ostatnie SNR'; + + @override + String get repeater_noiseFloor => 'Poziom Szumów'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Statystyki pakietów'; + + @override + String get repeater_sent => 'Wysłane'; + + @override + String get repeater_received => 'Otrzymano'; + + @override + String get repeater_duplicates => 'Powtórzenia'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days dni ${hours}h ${minutes}m ${seconds}s'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Razem: $total, Powodzenie: $flood, Bezpośrednio: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Razem: $total, Powodzenie: $flood, Bezpośrednio: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Powodzie: $flood, Bezpośrednie: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Razem: $total'; + } + + @override + String get repeater_settingsTitle => 'Ustawienia Powtórki'; + + @override + String get repeater_basicSettings => 'Podstawowe Ustawienia'; + + @override + String get repeater_repeaterName => 'Nazwa Powtórnika'; + + @override + String get repeater_repeaterNameHelper => 'Wyświetl nazwę tego powtarzacza'; + + @override + String get repeater_adminPassword => 'Hasło Administracyjne'; + + @override + String get repeater_adminPasswordHelper => 'Pełny dostęp hasło'; + + @override + String get repeater_guestPassword => 'Hasło gościa'; + + @override + String get repeater_guestPasswordHelper => 'Dostęp tylko do odczytu hasło'; + + @override + String get repeater_radioSettings => 'Ustawienia radia'; + + @override + String get repeater_frequencyMhz => 'Częstotliwość (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Power'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Przepustowość'; + + @override + String get repeater_spreadingFactor => 'Rozkład Czynnika'; + + @override + String get repeater_codingRate => 'Stawka kodowania'; + + @override + String get repeater_locationSettings => 'Ustawienia Lokalizacji'; + + @override + String get repeater_latitude => 'Szerokość'; + + @override + String get repeater_latitudeHelper => 'Stopnie dziesiętne (np. 37.7749)'; + + @override + String get repeater_longitude => 'Długość'; + + @override + String get repeater_longitudeHelper => 'Stopnie dziesiętne (np. -122,4194)'; + + @override + String get repeater_features => 'Funkcje'; + + @override + String get repeater_packetForwarding => 'Przekierowanie pakietów'; + + @override + String get repeater_packetForwardingSubtitle => + 'Włącz repeater, aby przekazywać pakiety.'; + + @override + String get repeater_guestAccess => 'Dostęp dla gości'; + + @override + String get repeater_guestAccessSubtitle => + 'Umożliw dostęp tylko do odczytu dla gości.'; + + @override + String get repeater_privacyMode => 'Tryb Prywatności'; + + @override + String get repeater_privacyModeSubtitle => + 'Ukryj imię/lokalizację w reklamach'; + + @override + String get repeater_advertisementSettings => 'Ustawienia Reklam'; + + @override + String get repeater_localAdvertInterval => 'Interwał Reklamy Lokalnej'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes minut'; + } + + @override + String get repeater_floodAdvertInterval => 'Interwał Reklamy Powodziowej'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours godzin'; + } + + @override + String get repeater_encryptedAdvertInterval => + 'Zaszyfrowany Interwał Reklamowy'; + + @override + String get repeater_dangerZone => 'Strefa Zagrożeń'; + + @override + String get repeater_rebootRepeater => 'Zrestartuj Powtarzacz'; + + @override + String get repeater_rebootRepeaterSubtitle => + 'Zrestartuj urządzenie powtarzające.'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Czy na pewno chcesz zrestartować ten repeater?'; + + @override + String get repeater_regenerateIdentityKey => 'Wygeneruj klucz tożsamości'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Wygeneruj nową parę kluczy publicznych/prywatnych'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'To zostanie wygenerowane nowe tożsamość dla powtarzacza. Kontynuować?'; + + @override + String get repeater_eraseFileSystem => 'Wyczyść System Plików'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Sformatuj system plików powielacza'; + + @override + String get repeater_eraseFileSystemConfirm => + 'OSTRZEŻENIE: To spowoduje usunięcie wszystkich danych z powtarzacza. Nie da się tego cofnąć!'; + + @override + String get repeater_eraseSerialOnly => + 'Usunięcie jest dostępne tylko przez konsolę szeregową.'; + + @override + String repeater_commandSent(String command) { + return 'Polecenie wysłane: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Błąd podczas wysyłania polecenia: $error'; + } + + @override + String get repeater_confirm => 'Potwierdź'; + + @override + String get repeater_settingsSaved => 'Ustawienia zostały pomyślnie zapisane.'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Błąd zapisu ustawień: $error'; + } + + @override + String get repeater_refreshBasicSettings => 'Odśwież Podstawowe Ustawienia'; + + @override + String get repeater_refreshRadioSettings => 'Odśwież Ustawienia Radio'; + + @override + String get repeater_refreshTxPower => 'Odśwież TX power'; + + @override + String get repeater_refreshLocationSettings => + 'Odśwież Ustawienia Lokalizacji'; + + @override + String get repeater_refreshPacketForwarding => 'Odśwież trasowanie pakietów'; + + @override + String get repeater_refreshGuestAccess => 'Odśwież dostęp gościa'; + + @override + String get repeater_refreshPrivacyMode => 'Odśwież Tryb Prywatności'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Odśwież Ustawienia Reklamy'; + + @override + String repeater_refreshed(String label) { + return '$label odświeżone'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Błąd podczas odświeżania $label'; + } + + @override + String get repeater_cliTitle => 'Powtarzacz CLI'; + + @override + String get repeater_debugNextCommand => 'Debug Następną Komendę'; + + @override + String get repeater_commandHelp => 'Pomoc'; + + @override + String get repeater_clearHistory => 'Wyczyść historię'; + + @override + String get repeater_noCommandsSent => 'Nie wysłano jeszcze żadnych poleceń'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Wprowadź polecenie poniżej lub użyj szybkich poleceń'; + + @override + String get repeater_enterCommandHint => 'Wprowadź polecenie...'; + + @override + String get repeater_previousCommand => 'Poprzednia komenda'; + + @override + String get repeater_nextCommand => 'Następna komenda'; + + @override + String get repeater_enterCommandFirst => 'Wprowadź najpierw polecenie'; + + @override + String get repeater_cliCommandFrameTitle => 'Określony Wyraz Polecenia CLI'; + + @override + String repeater_cliCommandError(String error) { + return 'Błąd: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Pobierz imię'; + + @override + String get repeater_cliQuickGetRadio => 'Uzyskaj Radio'; + + @override + String get repeater_cliQuickGetTx => 'Pobierz TX'; + + @override + String get repeater_cliQuickNeighbors => 'Sąsiedzi'; + + @override + String get repeater_cliQuickVersion => 'Wersja'; + + @override + String get repeater_cliQuickAdvertise => 'Reklama'; + + @override + String get repeater_cliQuickClock => 'Godzina'; + + @override + String get repeater_cliHelpAdvert => 'Wysyła pakiet reklamowy'; + + @override + String get repeater_cliHelpReboot => + 'Zresetuj urządzenie. (Uwaga, może pojawić się \'Timeout\', co jest normalne)'; + + @override + String get repeater_cliHelpClock => + 'Wyświetla aktualny czas zgodnie z zegarem urządzenia.'; + + @override + String get repeater_cliHelpPassword => + 'Ustawia nowe hasło administratora dla urządzenia.'; + + @override + String get repeater_cliHelpVersion => + 'Wyświetla wersję urządzenia i datę budowy oprogramowania.'; + + @override + String get repeater_cliHelpClearStats => + 'Resetuje różne wskaźniki statystyk do zera.'; + + @override + String get repeater_cliHelpSetAf => 'Ustawia czynnik czasu powietrznego.'; + + @override + String get repeater_cliHelpSetTx => + 'Ustawia moc transmisji LoRa w dBm. (zrestartuj, aby zastosować)'; + + @override + String get repeater_cliHelpSetRepeat => + 'Włącza lub wyłącza rolę powtarzacza dla tego węzła.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Serwer pokoju) Jeśli \'włączone\', to logowanie z pustym hasłem będzie dozwolone, ale nie można publikować w pokoju (tylko czytać).'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Ustawia maksymalną liczbę skoków pakietu powrotnego (jeśli >= max, pakiet nie jest przekierowywany)'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Ustawia Próg Interferencji (w dB). Domyślnie wynosi 14. Ustaw na 0, aby wyłączyć wykrywanie zakłóceń kanału.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Ustawia interwał do zresetowania Automatycznego Sterownika Głośności. Ustaw na 0, aby wyłączyć.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Włącza lub wyłącza funkcję \'podwójnych potwierdzeń\'.'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Ustawia interwał timera w minutach do wysyłania pakietu reklamy lokalnej (bezpośredniej). Ustaw na 0, aby wyłączyć.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Ustawia interwał timera w godzinach do wysłania pakietu reklamowego typu \"powiew\". Ustaw na 0, aby wyłączyć.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Ustawia/aktualizuje hasło gościa. (dla repeaterów, loginy gości mogą wysyłać żądanie \"Get Stats\")'; + + @override + String get repeater_cliHelpSetName => 'Ustawia nazwę reklamy.'; + + @override + String get repeater_cliHelpSetLat => + 'Ustawia współrzędną geograficzne (w stopniach dziesiętnych) mapy reklam.'; + + @override + String get repeater_cliHelpSetLon => + 'Ustawia współrzędną długościową mapy reklamy. (stopnie dziesiętne)'; + + @override + String get repeater_cliHelpSetRadio => + 'Ustawia nowe parametry radia i zapisuje je w preferencjach. Wymaga polecenia \"reboot\" do zastosowania.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Ustawienia (eksperymentalne) bazowe (muszą być > 1, aby działać) do stosowania lekkiego opóźnienia dla odebranych pakietów, w oparciu o siłę sygnału/wynik. Ustaw na 0, aby wyłączyć.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Ustawia czynnik mnożony przez czas utrzymania w trybie zalewowym dla pakietu oraz z wykorzystaniem losowego systemu slotów, aby opóźnić jego przesyłanie (zmniejszając prawdopodobieństwo kolizji).'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Taki sam jak txdelay, ale dla stosowania losowej opóźnienia przy przekazywaniu pakietów w trybie bezpośrednim.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => 'Włącz/Wyłącz mostek.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Ustaw czas opóźnienia przed ponownym wysyłaniem pakietów.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Wybierz, czy most będzie ponownie transmitował otrzymywane pakiety, czy też wysyłane.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Ustaw prędkość transmisji magistrali szeregowej dla mostów rs232.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Ustaw sekret dla mostów ESPNOW.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Ustawia niestandardowy współczynnik do korekty zgłaszanego napięcia baterii (obsługa tylko na wybranych płytach).'; + + @override + String get repeater_cliHelpTempRadio => + 'Ustawia tymczasowe parametry radia na podany czas trwania w minutach, a następnie powraca do oryginalnych parametrów radia. (nie zapisuje zmian w preferencjach).'; + + @override + String get repeater_cliHelpSetPerm => + 'Modyfikuje ACL. Usuwa dopasowaną wpis (z prefiksem pubkey), jeśli \"permissions\" wynosi zero. Dodaje nowy wpis, jeśli pubkey-hex ma pełną długość i nie znajduje się obecnie w ACL. Aktualizuje wpis, dopasowując prefiks pubkey. Bit uprawnień zależy od roli firmware, ale dolne 2 bity to: 0 (Gość), 1 (tylko odczyt), 2 (odczyt i zapis), 3 (administrator).'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Uzyskano typ mostu: brak, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => + 'Rozpoczyna się logowanie pakietów do systemu plików.'; + + @override + String get repeater_cliHelpLogStop => + 'Zatrzymuje logowanie pakietów do systemu plików.'; + + @override + String get repeater_cliHelpLogErase => + 'Usuwa logi pakietów z systemu plików.'; + + @override + String get repeater_cliHelpNeighbors => + 'Wyświetla listę innych węzłów powtarzających się, które usłyszano dzięki reklamom zero-hop. Każda linia to: id-prefix-hex:timestamp:snr-times-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Usuwa pierwszy pasujący wpis (z prefiksem pubkey (hex)) z listy sąsiadów.'; + + @override + String get repeater_cliHelpRegion => + '(tylko seria) Wyświetla wszystkie zdefiniowane regiony i aktualne uprawnienia do powodzi.'; + + @override + String get repeater_cliHelpRegionLoad => + 'ZAPOMNIJ: to jest specjalne wywołanie wielokomendowe. Każda następna komenda jest nazwą regionu (wcięta spacjami, aby wskazywać hierarchię nadrzędną, z minimum jedną spacją). Zakończona wysłaniem pustej linii/komendy.'; + + @override + String get repeater_cliHelpRegionGet => + 'Wyszukuje region o podanej nazwie prefiksu (lub \"\" dla zakresu globalnego). Odpowiada \"-> region-name (parent-name) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Dodaje lub aktualizuje definicję regionu z podaną nazwą.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Usuwa definicję regionu o podanej nazwie. (musi się dokładnie zgadzać i nie może mieć podregionów).'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Ustawia uprawnienia \'P\'łytkowe dla podanego regionu. (\'\' dla zakresu globalnego/starszego)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Usuwa uprawnienie \'Pływające\' dla podanej strefy. (ZALECANE: na tym etapie NIE zaleca się używania tego na globalnym/starszym zakresie!!).'; + + @override + String get repeater_cliHelpRegionHome => + 'Odpowiada z aktualnej \'home\' region. (Uwaga: nie zostało jeszcze zastosowane, zarezerwowane na przyszłość).'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Ustawia region \'domowe\'.'; + + @override + String get repeater_cliHelpRegionSave => + 'Zapisuje listę/mapę regionów do pamięci.'; + + @override + String get repeater_cliHelpGps => + 'Wyświetla status GPS. Jeśli GPS jest wyłączony, odpowiada tylko \"off\", jeśli jest włączony, odpowiada z \"on\", \"status\", \"fix\", liczbą satelitów.'; + + @override + String get repeater_cliHelpGpsOnOff => 'Włącza/wyłącza nawigację GPS.'; + + @override + String get repeater_cliHelpGpsSync => + 'Synchronizuje czas węzła z zegarem GPS.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Ustawia pozycję węzła na współrzędne GPS i zapisuje preferencje.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Udostępnia konfigurację reklamy lokalizacji węzła:\n- brak: nie uwzględniaj lokalizacji w reklamach\n- udostępnia: udostępnia lokalizację GPS (z SensorManager)\n- ustawienia: reklamuj lokalizację przechowywaną w ustawieniach'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Ustawia konfigurację reklamy w lokalizacji.'; + + @override + String get repeater_commandsListTitle => 'Lista poleceń'; + + @override + String get repeater_commandsListNote => + 'ZAPAMIĘTAJ: dla różnych poleceń \"set ...\" istnieje również polecenie \"get ...\".'; + + @override + String get repeater_general => 'Ogólne'; + + @override + String get repeater_settingsCategory => 'Ustawienia'; + + @override + String get repeater_bridge => 'Most'; + + @override + String get repeater_logging => 'Rejestrowanie'; + + @override + String get repeater_neighborsRepeaterOnly => 'Sąsiedzi (tylko powtarzacz)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Zarządzanie Regionem (tylko Powtarzacz)'; + + @override + String get repeater_regionNote => + 'Wprowadzono komendy regionalne w celu zarządzania definicjami i uprawnieniami regionów.'; + + @override + String get repeater_gpsManagement => 'Zarządzanie GPS'; + + @override + String get repeater_gpsNote => + 'Polecenie GPS zostało wprowadzone w celu zarządzania tematami związanymi z lokalizacją.'; + + @override + String get telemetry_receivedData => 'Otrzymano Dane Telemetrii'; + + @override + String get telemetry_requestTimeout => + 'Życzenie o danych telemetrycznych nie udało się.'; + + @override + String telemetry_errorLoading(String error) { + return 'Błąd podczas ładowania telemetry: $error'; + } + + @override + String get telemetry_noData => 'Brak dostępnych danych telemetrycznych.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Kanał $channel'; + } + + @override + String get telemetry_batteryLabel => 'Bateria'; + + @override + String get telemetry_voltageLabel => 'Napięcie'; + + @override + String get telemetry_mcuTemperatureLabel => 'Temperatura MCU'; + + @override + String get telemetry_temperatureLabel => 'Temperatura'; + + @override + String get telemetry_currentLabel => 'Obecny'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}W'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Ścieżka pakietu'; + + @override + String get channelPath_viewMap => 'Wyświetl mapę'; + + @override + String get channelPath_otherObservedPaths => 'Inne Zauważone Ścieżki'; + + @override + String get channelPath_repeaterHops => 'Skoki Powtórki'; + + @override + String get channelPath_noHopDetails => + 'Szczegóły dotyczące tego pakietu nie zostały podane.'; + + @override + String get channelPath_messageDetails => 'Szczegóły wiadomości'; + + @override + String get channelPath_senderLabel => 'Nadawca'; + + @override + String get channelPath_timeLabel => 'Czas'; + + @override + String get channelPath_repeatsLabel => 'Powtórzenia'; + + @override + String channelPath_pathLabel(int index) { + return 'Ścieżka $index'; + } + + @override + String get channelPath_observedLabel => 'Obserwowane'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Obserwowany ścieżka $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'Brak danych lokalizacyjnych'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Nieznane'; + + @override + String get channelPath_floodPath => 'Powodzenie'; + + @override + String get channelPath_directPath => 'Bezpośrednio'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 z $total skoków'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed z $total skoków'; + } + + @override + String get channelPath_mapTitle => 'Mapa ścieżek'; + + @override + String get channelPath_noRepeaterLocations => + 'Brak dostępnych lokalizacji powtarzaczy dla tego ścieżki.'; + + @override + String channelPath_primaryPath(int index) { + return 'Ścieżka $index (Główna)'; + } + + @override + String get channelPath_pathLabelTitle => 'Ścieżka'; + + @override + String get channelPath_observedPathHeader => 'Obserwowana ścieżka'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'Brak dostępnych szczegółów hopa dla tego pakietu.'; + + @override + String get channelPath_unknownRepeater => 'Nieznany Powtarzacz'; + + @override + String get listFilter_tooltip => 'Filtruj i sortuj'; + + @override + String get listFilter_sortBy => 'Sortuj po'; + + @override + String get listFilter_latestMessages => 'Najnowsze wiadomości'; + + @override + String get listFilter_heardRecently => 'Słyszano niedawno'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Filtry'; + + @override + String get listFilter_all => 'Wszystko'; + + @override + String get listFilter_users => 'Użytkownicy'; + + @override + String get listFilter_repeaters => 'Powtarzacze'; + + @override + String get listFilter_roomServers => 'Serwery pokoju'; + + @override + String get listFilter_unreadOnly => 'Tylko nieprzeczytane'; + + @override + String get listFilter_newGroup => 'Nowa grupa'; +} diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart new file mode 100644 index 0000000..403c4d6 --- /dev/null +++ b/lib/l10n/app_localizations_pt.dart @@ -0,0 +1,2389 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Portuguese (`pt`). +class AppLocalizationsPt extends AppLocalizations { + AppLocalizationsPt([String locale = 'pt']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Contactos'; + + @override + String get nav_channels => 'Canais'; + + @override + String get nav_map => 'Mapa'; + + @override + String get common_cancel => 'Cancelar'; + + @override + String get common_connect => 'Conectar'; + + @override + String get common_unknownDevice => 'Dispositivo Desconhecido'; + + @override + String get common_save => 'Salvar'; + + @override + String get common_delete => 'Excluir'; + + @override + String get common_close => 'Fechar'; + + @override + String get common_edit => 'Editar'; + + @override + String get common_add => 'Adicionar'; + + @override + String get common_settings => 'Configurações'; + + @override + String get common_disconnect => 'Desconectar'; + + @override + String get common_connected => 'Conectado'; + + @override + String get common_disconnected => 'Desconectado'; + + @override + String get common_create => 'Criar'; + + @override + String get common_continue => 'Continuar'; + + @override + String get common_share => 'Compartilhar'; + + @override + String get common_copy => 'Copiar'; + + @override + String get common_retry => 'Tentar novamente'; + + @override + String get common_hide => 'Esconder'; + + @override + String get common_remove => 'Remover'; + + @override + String get common_enable => 'Ativar'; + + @override + String get common_disable => 'Desativar'; + + @override + String get common_reboot => 'Reiniciar'; + + @override + String get common_loading => 'Carregando...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Procurando por dispositivos...'; + + @override + String get scanner_connecting => 'Conectando...'; + + @override + String get scanner_disconnecting => 'Desconectando...'; + + @override + String get scanner_notConnected => 'Não está conectado'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Conectado a $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Procurando dispositivos MeshCore...'; + + @override + String get scanner_tapToScan => + 'Toque em \"Escanear\" para encontrar dispositivos MeshCore'; + + @override + String scanner_connectionFailed(String error) { + return 'Falha na conexão: $error'; + } + + @override + String get scanner_stop => 'Pare'; + + @override + String get scanner_scan => 'Digitalizar'; + + @override + String get device_quickSwitch => 'Mudar rapidamente'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Configurações'; + + @override + String get settings_deviceInfo => 'Informações do Dispositivo'; + + @override + String get settings_appSettings => 'Configurações do App'; + + @override + String get settings_appSettingsSubtitle => + 'Notificações, mensagens e preferências de mapa'; + + @override + String get settings_nodeSettings => 'Configurações do Nó'; + + @override + String get settings_nodeName => 'Nome do Nó'; + + @override + String get settings_nodeNameNotSet => 'Não definido'; + + @override + String get settings_nodeNameHint => 'Insira o nome do nó'; + + @override + String get settings_nodeNameUpdated => 'Nome atualizado'; + + @override + String get settings_radioSettings => 'Configurações de Rádio'; + + @override + String get settings_radioSettingsSubtitle => + 'Frequência, potência, fator de espalhamento'; + + @override + String get settings_radioSettingsUpdated => + 'Configurações de rádio atualizadas'; + + @override + String get settings_location => 'Localização'; + + @override + String get settings_locationSubtitle => 'Coordenadas GPS'; + + @override + String get settings_locationUpdated => 'Localização atualizada'; + + @override + String get settings_locationBothRequired => + 'Insira a latitude e a longitude.'; + + @override + String get settings_locationInvalid => 'Latitude ou longitude inválidos.'; + + @override + String get settings_latitude => 'Latitude'; + + @override + String get settings_longitude => 'Longitude'; + + @override + String get settings_privacyMode => 'Modo de Privacidade'; + + @override + String get settings_privacyModeSubtitle => + 'Esconder nome/localização em anúncios'; + + @override + String get settings_privacyModeToggle => + 'Ative o modo de privacidade para ocultar seu nome e localização em anúncios.'; + + @override + String get settings_privacyModeEnabled => 'Modo de privacidade ativado'; + + @override + String get settings_privacyModeDisabled => 'Modo de privacidade desativado'; + + @override + String get settings_actions => 'Ações'; + + @override + String get settings_sendAdvertisement => 'Enviar Publicidade'; + + @override + String get settings_sendAdvertisementSubtitle => + 'Presença de transmissão agora'; + + @override + String get settings_advertisementSent => 'Anúncio enviado'; + + @override + String get settings_syncTime => 'Tempo de Sincronização'; + + @override + String get settings_syncTimeSubtitle => + 'Definir o relógio do dispositivo para o horário do telefone'; + + @override + String get settings_timeSynchronized => 'Sincronizado com o tempo'; + + @override + String get settings_refreshContacts => 'Atualizar Contatos'; + + @override + String get settings_refreshContactsSubtitle => + 'Recarregar a lista de contatos do dispositivo'; + + @override + String get settings_rebootDevice => 'Reiniciar Dispositivo'; + + @override + String get settings_rebootDeviceSubtitle => + 'Reiniciar o dispositivo MeshCore'; + + @override + String get settings_rebootDeviceConfirm => + 'Tem certeza de que deseja reiniciar o dispositivo? Você será desconectado.'; + + @override + String get settings_debug => 'Depurar'; + + @override + String get settings_bleDebugLog => 'Log de Depuração BLE'; + + @override + String get settings_bleDebugLogSubtitle => + 'Comandos, respostas e dados brutos do BLE'; + + @override + String get settings_appDebugLog => 'Log de Depuração do Aplicativo'; + + @override + String get settings_appDebugLogSubtitle => + 'Mensagens de depuração do aplicativo'; + + @override + String get settings_about => 'Sobre'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => 'Projeto MeshCore de Código Aberto 2024'; + + @override + String get settings_aboutDescription => + 'Um cliente Flutter de código aberto para dispositivos de rede mesh LoRa Core da MeshCore.'; + + @override + String get settings_infoName => 'Nome'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'Status'; + + @override + String get settings_infoBattery => 'Bateria'; + + @override + String get settings_infoPublicKey => 'Chave Pública'; + + @override + String get settings_infoContactsCount => 'Número de Contatos'; + + @override + String get settings_infoChannelCount => 'Número do Canal'; + + @override + String get settings_presets => 'Presets'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Frequência (MHz)'; + + @override + String get settings_frequencyHelper => '300,0 - 2500,0'; + + @override + String get settings_frequencyInvalid => 'Frequência inválida (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Largura de banda'; + + @override + String get settings_spreadingFactor => 'Fator de Dispersão'; + + @override + String get settings_codingRate => 'Taxa de Codificação'; + + @override + String get settings_txPower => 'TX Potência (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Potência de TX inválida (0-22 dBm)'; + + @override + String get settings_longRange => 'Alcance Longo'; + + @override + String get settings_fastSpeed => 'Velocidade Rápida'; + + @override + String settings_error(String message) { + return 'Erro: $message'; + } + + @override + String get appSettings_title => 'Configurações do App'; + + @override + String get appSettings_appearance => 'Aparência'; + + @override + String get appSettings_theme => 'Tema'; + + @override + String get appSettings_themeSystem => 'Padrão do sistema'; + + @override + String get appSettings_themeLight => 'Luz'; + + @override + String get appSettings_themeDark => 'Escuro'; + + @override + String get appSettings_language => 'Idioma'; + + @override + String get appSettings_languageSystem => 'Padrão do sistema'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Notificações'; + + @override + String get appSettings_enableNotifications => 'Ativar Notificações'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Receber notificações para mensagens e anúncios'; + + @override + String get appSettings_notificationPermissionDenied => + 'Permissão de notificação negada'; + + @override + String get appSettings_notificationsEnabled => 'Notificações ativadas'; + + @override + String get appSettings_notificationsDisabled => 'Notificações desativadas'; + + @override + String get appSettings_messageNotifications => 'Notificações de Mensagem'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Mostrar notificação ao receber novas mensagens'; + + @override + String get appSettings_channelMessageNotifications => + 'Notificações de Mensagens do Canal'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Mostrar notificação ao receber mensagens do canal'; + + @override + String get appSettings_advertisementNotifications => + 'Notificações de Anúncios'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Mostrar notificação quando novos nós forem descobertos'; + + @override + String get appSettings_messaging => 'Mensagens'; + + @override + String get appSettings_clearPathOnMaxRetry => + 'Limpar Caminho em Tentativas Máximas'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Redefinir o caminho de contato após 5 tentativas de envio falhas'; + + @override + String get appSettings_pathsWillBeCleared => + 'Os caminhos serão limpos após 5 tentativas falhas.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Os caminhos não serão limpos automaticamente.'; + + @override + String get appSettings_autoRouteRotation => 'Rotação de Rota Automática'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Alternar entre os melhores caminhos e o modo inundação'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Rotação de roteamento automático habilitada'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Rotação de roteamento automático desativada'; + + @override + String get appSettings_battery => 'Bateria'; + + @override + String get appSettings_batteryChemistry => 'Química da Bateria'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Definir por dispositivo ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Conecte-se a um dispositivo para escolher'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6-3,65V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + + @override + String get appSettings_mapDisplay => 'Exibição do Mapa'; + + @override + String get appSettings_showRepeaters => 'Mostrar Repetidores'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Exibir nós de repetidor no mapa'; + + @override + String get appSettings_showChatNodes => 'Mostrar Nós de Chat'; + + @override + String get appSettings_showChatNodesSubtitle => 'Exibir nós de chat no mapa'; + + @override + String get appSettings_showOtherNodes => 'Mostrar Outros Nós'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Exibir outros tipos de nó no mapa'; + + @override + String get appSettings_timeFilter => 'Filtro de Tempo'; + + @override + String get appSettings_timeFilterShowAll => 'Mostrar todos os nós'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Mostrar nós das últimas $hours horas'; + } + + @override + String get appSettings_mapTimeFilter => 'Filtro de Tempo do Mapa'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Mostrar nós descobertos dentro de:'; + + @override + String get appSettings_allTime => 'Todos os tempos'; + + @override + String get appSettings_lastHour => 'Última hora'; + + @override + String get appSettings_last6Hours => 'Últimos 6 horas'; + + @override + String get appSettings_last24Hours => 'Últimas 24 horas'; + + @override + String get appSettings_lastWeek => 'Da última semana'; + + @override + String get appSettings_offlineMapCache => 'Cache de Mapa Offline'; + + @override + String get appSettings_noAreaSelected => 'Nenhuma área selecionada'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Área selecionada (zoom $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Depurar'; + + @override + String get appSettings_appDebugLogging => + 'Rastreamento de Depuração do Aplicativo'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Registrar mensagens de depuração do aplicativo Log para solucionar problemas'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'Log de depuração do aplicativo habilitado'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'O registro de depuração do aplicativo está desativado.'; + + @override + String get contacts_title => 'Contactos'; + + @override + String get contacts_noContacts => 'Ainda não existem contatos.'; + + @override + String get contacts_contactsWillAppear => + 'Os contatos serão exibidos quando os dispositivos anunciarem.'; + + @override + String get contacts_searchContacts => 'Pesquisar contatos...'; + + @override + String get contacts_noUnreadContacts => 'Sem contatos não lidos.'; + + @override + String get contacts_noContactsFound => + 'Não foram encontrados contatos ou grupos.'; + + @override + String get contacts_deleteContact => 'Excluir Contato'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Remover $contactName dos contatos?'; + } + + @override + String get contacts_manageRepeater => 'Gerenciar Repetidor'; + + @override + String get contacts_roomLogin => 'Login no Quarto'; + + @override + String get contacts_openChat => 'Abrir Chat'; + + @override + String get contacts_editGroup => 'Editar Grupo'; + + @override + String get contacts_deleteGroup => 'Excluir Grupo'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Remover $groupName?'; + } + + @override + String get contacts_newGroup => 'Novo Grupo'; + + @override + String get contacts_groupName => 'Nome do grupo'; + + @override + String get contacts_groupNameRequired => 'O nome do grupo é obrigatório.'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'O grupo \"$name\" já existe'; + } + + @override + String get contacts_filterContacts => 'Filtrar contatos...'; + + @override + String get contacts_noContactsMatchFilter => + 'Não existem contatos que correspondam ao seu filtro'; + + @override + String get contacts_noMembers => 'Nenhum membro'; + + @override + String get contacts_lastSeenNow => 'Última vez que foi visto agora'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Última vez que foi visto $minutes minutos atrás'; + } + + @override + String get contacts_lastSeenHourAgo => 'Última vez que foi visto há 1 hora.'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Última vez visto $hours horas atrás'; + } + + @override + String get contacts_lastSeenDayAgo => 'Última vez que foi visto 1 dia atrás'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Última vez visto $days dias atrás'; + } + + @override + String get channels_title => 'Canais'; + + @override + String get channels_noChannelsConfigured => 'Nenhuma canalização configurada'; + + @override + String get channels_addPublicChannel => 'Adicionar Canal Público'; + + @override + String get channels_searchChannels => 'Pesquisar canais...'; + + @override + String get channels_noChannelsFound => 'Nenhum canal encontrado'; + + @override + String channels_channelIndex(int index) { + return 'Canal $index'; + } + + @override + String get channels_hashtagChannel => 'Canal com hashtag'; + + @override + String get channels_public => 'Público'; + + @override + String get channels_private => 'Privado'; + + @override + String get channels_publicChannel => 'Canal público'; + + @override + String get channels_privateChannel => 'Canal privado'; + + @override + String get channels_editChannel => 'Editar canal'; + + @override + String get channels_deleteChannel => 'Excluir canal'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Excluir \"$name\"? Não pode ser desfeito.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Canal \"$name\" excluído'; + } + + @override + String get channels_addChannel => 'Adicionar Canal'; + + @override + String get channels_channelIndexLabel => 'Índice do Canal'; + + @override + String get channels_channelName => 'Nome do Canal'; + + @override + String get channels_usePublicChannel => 'Usar Canal Público'; + + @override + String get channels_standardPublicPsk => 'PSK público padrão'; + + @override + String get channels_pskHex => 'PSK (Hex)'; + + @override + String get channels_generateRandomPsk => 'Gerar PSK aleatório'; + + @override + String get channels_enterChannelName => 'Por favor, insira um nome de canal'; + + @override + String get channels_pskMustBe32Hex => + 'O PSK deve ter 32 caracteres hexadecimais.'; + + @override + String channels_channelAdded(String name) { + return 'Canal \"$name\" adicionado'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Editar Canal $index'; + } + + @override + String get channels_smazCompression => 'Compressão SMAZ'; + + @override + String channels_channelUpdated(String name) { + return 'Canal \"$name\" atualizado'; + } + + @override + String get channels_publicChannelAdded => 'Canal público adicionado'; + + @override + String get channels_sortBy => 'Ordenar por'; + + @override + String get channels_sortManual => 'Manual'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => 'Últimas mensagens'; + + @override + String get channels_sortUnread => 'Não lido'; + + @override + String get chat_noMessages => 'Ainda não existem mensagens.'; + + @override + String get chat_sendMessageToStart => 'Enviar uma mensagem para começar'; + + @override + String get chat_originalMessageNotFound => 'Mensagem original não encontrada'; + + @override + String chat_replyingTo(String name) { + return 'Responder a $name'; + } + + @override + String chat_replyTo(String name) { + return 'Responder a $name'; + } + + @override + String get chat_location => 'Localização'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Enviar uma mensagem para $contactName'; + } + + @override + String get chat_typeMessage => 'Digite uma mensagem...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Mensagem muito longa (máximo $maxBytes bytes).'; + } + + @override + String get chat_messageCopied => 'Mensagem copiada'; + + @override + String get chat_messageDeleted => 'Mensagem excluída'; + + @override + String get chat_retryingMessage => 'Tentando novamente'; + + @override + String chat_retryCount(int current, int max) { + return 'Tentar $current/$max'; + } + + @override + String get chat_sendGif => 'Enviar GIF'; + + @override + String get chat_reply => 'Responder'; + + @override + String get chat_addReaction => 'Adicionar Reação'; + + @override + String get chat_me => 'Eu'; + + @override + String get emojiCategorySmileys => 'Emojis'; + + @override + String get emojiCategoryGestures => 'Gestos'; + + @override + String get emojiCategoryHearts => 'Corações'; + + @override + String get emojiCategoryObjects => 'Objetos'; + + @override + String get gifPicker_title => 'Escolher um GIF'; + + @override + String get gifPicker_searchHint => 'Pesquisar GIFs...'; + + @override + String get gifPicker_poweredBy => 'Desenvolvido por GIPHY'; + + @override + String get gifPicker_noGifsFound => 'Nenhum GIF encontrado'; + + @override + String get gifPicker_failedLoad => 'Não foi possível carregar os GIFs'; + + @override + String get gifPicker_failedSearch => 'Falha na pesquisa de GIFs'; + + @override + String get gifPicker_noInternet => 'Sem conexão com a internet'; + + @override + String get debugLog_appTitle => 'Log de Depuração do Aplicativo'; + + @override + String get debugLog_bleTitle => 'Log de Depuração BLE'; + + @override + String get debugLog_copyLog => 'Copiar log'; + + @override + String get debugLog_clearLog => 'Limpar log'; + + @override + String get debugLog_copied => 'Log de depuração copiado'; + + @override + String get debugLog_bleCopied => 'Log BLE copiado'; + + @override + String get debugLog_noEntries => 'Ainda não existem logs de depuração.'; + + @override + String get debugLog_enableInSettings => + 'Ativar o log de depuração do aplicativo nas configurações'; + + @override + String get debugLog_frames => 'Estruturas'; + + @override + String get debugLog_rawLogRx => 'Log Raw-RX'; + + @override + String get debugLog_noBleActivity => 'Ainda não há atividade BLE.'; + + @override + String debugFrame_length(int count) { + return 'Comprimento do Quadro: $count bytes'; + } + + @override + String debugFrame_command(String value) { + return 'Comando: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Mensagem de Texto:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Destino PubKey: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Timestamp: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Bandeiras: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Tipo de Texto: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Simples'; + + @override + String debugFrame_text(String text) { + return '- Texto: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Espaço Hexadecimal:'; + + @override + String get chat_pathManagement => 'Gerenciamento de Caminhos'; + + @override + String get chat_routingMode => 'Modo de roteamento'; + + @override + String get chat_autoUseSavedPath => 'Auto (usar caminho salvo)'; + + @override + String get chat_forceFloodMode => 'Modo de Inundação Forçado'; + + @override + String get chat_recentAckPaths => 'Rotas de ACK Recentes (toque para usar):'; + + @override + String get chat_pathHistoryFull => + 'O histórico está cheio. Remova entradas para adicionar novas.'; + + @override + String get chat_hopSingular => 'pule'; + + @override + String get chat_hopPlural => 'salta'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'Sucessos'; + + @override + String get chat_removePath => 'Remover caminho'; + + @override + String get chat_noPathHistoryYet => + 'Ainda não há histórico de caminhos.\nEnvie uma mensagem para descobrir caminhos.'; + + @override + String get chat_pathActions => 'Ações do Caminho:'; + + @override + String get chat_setCustomPath => 'Definir Caminho Personalizado'; + + @override + String get chat_setCustomPathSubtitle => + 'Especifique manualmente o caminho de roteamento'; + + @override + String get chat_clearPath => 'Limpar Caminho'; + + @override + String get chat_clearPathSubtitle => + 'Forçar a descoberta na próxima transmissão'; + + @override + String get chat_pathCleared => + 'Caminho limpo. A próxima mensagem redescobrirá a rota.'; + + @override + String get chat_floodModeSubtitle => + 'Use a chave de roteamento na barra de ferramentas'; + + @override + String get chat_floodModeEnabled => + 'Modo de inundação ativado. Desative-o novamente através do ícone de roteamento na barra de ferramentas.'; + + @override + String get chat_fullPath => 'Caminho Completo'; + + @override + String get chat_pathDetailsNotAvailable => + 'Os detalhes do caminho ainda não estão disponíveis. Tente enviar uma mensagem para atualizar.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Caminho definido: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Salvo localmente. Conectar para sincronizar.'; + + @override + String get chat_pathDeviceConfirmed => 'Dispositivo confirmado.'; + + @override + String get chat_pathDeviceNotConfirmed => 'Dispositivo ainda não confirmado.'; + + @override + String get chat_type => 'Digite'; + + @override + String get chat_path => 'Caminho'; + + @override + String get chat_publicKey => 'Chave Pública'; + + @override + String get chat_compressOutgoingMessages => 'Comprimir mensagens enviadas'; + + @override + String get chat_floodForced => 'Inundação (forçada)'; + + @override + String get chat_directForced => 'Direto (forçado)'; + + @override + String chat_hopsForced(int count) { + return '$count saltos (forçado)'; + } + + @override + String get chat_floodAuto => 'Inundação (automática)'; + + @override + String get chat_direct => 'Salvar'; + + @override + String get chat_poiShared => 'Ponto de Interesse Compartilhado'; + + @override + String chat_unread(int count) { + return 'Não lido: $count'; + } + + @override + String get map_title => 'Mapa de Nós'; + + @override + String get map_noNodesWithLocation => + 'Não existem nós com dados de localização.'; + + @override + String get map_nodesNeedGps => + 'Os nós precisam partilhar as suas coordenadas GPS\npara aparecerem no mapa'; + + @override + String map_nodesCount(int count) { + return 'Nós: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Pinos: $count'; + } + + @override + String get map_chat => 'Chat'; + + @override + String get map_repeater => 'Repetidor'; + + @override + String get map_room => 'Quarto'; + + @override + String get map_sensor => 'Sensor'; + + @override + String get map_pinDm => 'Gatilho (DM)'; + + @override + String get map_pinPrivate => 'Bloquear (Privado)'; + + @override + String get map_pinPublic => 'Pin (Público)'; + + @override + String get map_lastSeen => 'Última Visão'; + + @override + String get map_disconnectConfirm => + 'Tem certeza de que deseja desconectar deste dispositivo?'; + + @override + String get map_from => 'De'; + + @override + String get map_source => 'Fonte'; + + @override + String get map_flags => 'Bandeiras'; + + @override + String get map_shareMarkerHere => 'Compartilhar marcador aqui'; + + @override + String get map_pinLabel => 'Rótulo de marcador'; + + @override + String get map_label => 'Rótulo'; + + @override + String get map_pointOfInterest => 'Ponto de interesse'; + + @override + String get map_sendToContact => 'Enviar para o contato'; + + @override + String get map_sendToChannel => 'Enviar para o canal'; + + @override + String get map_noChannelsAvailable => 'Não existem canais disponíveis.'; + + @override + String get map_publicLocationShare => 'Compartilhar local público'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'Você está prestes a compartilhar uma localização em $channelLabel. Este canal é público e qualquer pessoa com a PSK pode visualizá-lo.'; + } + + @override + String get map_connectToShareMarkers => + 'Conecte-se a um dispositivo para compartilhar marcadores'; + + @override + String get map_filterNodes => 'Filtrar Nós'; + + @override + String get map_nodeTypes => 'Tipos de Nó'; + + @override + String get map_chatNodes => 'Nós de Chat'; + + @override + String get map_repeaters => 'Repetidores'; + + @override + String get map_otherNodes => 'Outros Nós'; + + @override + String get map_keyPrefix => 'Prefixo Chave'; + + @override + String get map_filterByKeyPrefix => 'Filtrar por prefixo-chave'; + + @override + String get map_publicKeyPrefix => 'Prefixo de chave pública'; + + @override + String get map_markers => 'Marcadores'; + + @override + String get map_showSharedMarkers => 'Mostrar marcadores compartilhados'; + + @override + String get map_lastSeenTime => 'Último Tempo de Visualização'; + + @override + String get map_sharedPin => 'Pin compartilhado'; + + @override + String get map_joinRoom => 'Junte-se à Sala'; + + @override + String get map_manageRepeater => 'Gerenciar Repetidor'; + + @override + String get mapCache_title => 'Cache de Mapa Offline'; + + @override + String get mapCache_selectAreaFirst => + 'Selecione uma área para armazenar em cache primeiro'; + + @override + String get mapCache_noTilesToDownload => + 'Não há tiles para baixar para esta área.'; + + @override + String get mapCache_downloadTilesTitle => 'Baixar tiles'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Baixar $count tiles para uso offline?'; + } + + @override + String get mapCache_downloadAction => 'Baixar'; + + @override + String mapCache_cachedTiles(int count) { + return 'Armazenados $count azulejos'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Tiles em cache ($downloaded) ($failed falhou)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => 'Limpar cache offline'; + + @override + String get mapCache_clearOfflineCachePrompt => + 'Remover todas as telhas de mapa em cache?'; + + @override + String get mapCache_offlineCacheCleared => 'Cache offline limpa'; + + @override + String get mapCache_noAreaSelected => 'Nenhuma área selecionada'; + + @override + String get mapCache_cacheArea => 'Área de Cache'; + + @override + String get mapCache_useCurrentView => 'Usar a Visualização Atual'; + + @override + String get mapCache_zoomRange => 'Intervalo de Zoom'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Estimados azulejos: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Baixado $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Baixar Tiles'; + + @override + String get mapCache_clearCacheButton => 'Limpar Cache'; + + @override + String mapCache_failedDownloads(int count) { + return 'Downloads falhas: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Agora'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes minutos atrás'; + } + + @override + String time_hoursAgo(int hours) { + return '${hours}h atrás'; + } + + @override + String time_daysAgo(int days) { + return '$days dias atrás'; + } + + @override + String get time_hour => 'hora'; + + @override + String get time_hours => 'horas'; + + @override + String get time_day => 'dia'; + + @override + String get time_days => 'dias'; + + @override + String get time_week => 'semana'; + + @override + String get time_weeks => 'semanas'; + + @override + String get time_month => 'mês'; + + @override + String get time_months => 'meses'; + + @override + String get time_minutes => 'minutos'; + + @override + String get time_allTime => 'Todos os tempos'; + + @override + String get dialog_disconnect => 'Desconectar'; + + @override + String get dialog_disconnectConfirm => + 'Tem certeza de que deseja desconectar deste dispositivo?'; + + @override + String get login_repeaterLogin => 'Login ao Repetidor'; + + @override + String get login_roomLogin => 'Login de Sala'; + + @override + String get login_password => 'Senha'; + + @override + String get login_enterPassword => 'Insira a senha'; + + @override + String get login_savePassword => 'Salvar senha'; + + @override + String get login_savePasswordSubtitle => + 'A senha será armazenada com segurança neste dispositivo.'; + + @override + String get login_repeaterDescription => + 'Insira a senha do repetidor para acessar as configurações e o status.'; + + @override + String get login_roomDescription => + 'Insira a senha da sala para acessar as configurações e o status.'; + + @override + String get login_routing => 'Rotas'; + + @override + String get login_routingMode => 'Modo de roteamento'; + + @override + String get login_autoUseSavedPath => 'Auto (usar caminho salvo)'; + + @override + String get login_forceFloodMode => 'Modo de Inundação Forçado'; + + @override + String get login_managePaths => 'Gerenciar Caminhos'; + + @override + String get login_login => 'Login'; + + @override + String login_attempt(int current, int max) { + return 'Tentar $current/$max'; + } + + @override + String login_failed(String error) { + return 'Login falhou: $error'; + } + + @override + String get common_reload => 'Recarregar'; + + @override + String get common_clear => 'Limpar'; + + @override + String path_currentPath(String path) { + return 'Caminho atual: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Usando $count $_temp0 caminho'; + } + + @override + String get path_enterCustomPath => 'Insira Caminho Personalizado'; + + @override + String get path_currentPathLabel => 'Caminho atual'; + + @override + String get path_hexPrefixInstructions => + 'Insira os prefixos hexadecimais de 2 caracteres para cada salto, separados por vírgulas.'; + + @override + String get path_hexPrefixExample => + 'A1,F2,3C (cada nó usa o primeiro byte de sua chave pública)'; + + @override + String get path_labelHexPrefixes => 'Prefixo Hexadecimal'; + + @override + String get path_helperMaxHops => + 'Máximo de 64 saltos. Cada prefixo tem 2 caracteres hexadecimais (1 byte)'; + + @override + String get path_selectFromContacts => 'Ou selecione de contatos:'; + + @override + String get path_noRepeatersFound => + 'Não foram encontrados repetidores ou servidores de sala.'; + + @override + String get path_customPathsRequire => + 'Caminhos personalizados exigem saltos intermediários que podem transmitir mensagens.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Prefixos hexadecimais inválidos: $prefixes'; + } + + @override + String get path_tooLong => + 'Caminho muito longo. Máximo de 64 saltos permitidos.'; + + @override + String get path_setPath => 'Definir Caminho'; + + @override + String get repeater_management => 'Gerenciamento de Repetidor'; + + @override + String get repeater_managementTools => 'Ferramentas de Gerenciamento'; + + @override + String get repeater_status => 'Status'; + + @override + String get repeater_statusSubtitle => + 'Visualizar status do repetidor, estatísticas e vizinhos.'; + + @override + String get repeater_telemetry => 'Telemetria'; + + @override + String get repeater_telemetrySubtitle => + 'Visualizar telemetria de sensores e estatísticas do sistema'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Enviar comandos ao repetidor'; + + @override + String get repeater_settings => 'Configurações'; + + @override + String get repeater_settingsSubtitle => 'Configurar parâmetros do repetidor'; + + @override + String get repeater_statusTitle => 'Status do Repetidor'; + + @override + String get repeater_routingMode => 'Modo de roteamento'; + + @override + String get repeater_autoUseSavedPath => 'Auto (usar caminho salvo)'; + + @override + String get repeater_forceFloodMode => 'Modo de Inundação Forçado'; + + @override + String get repeater_pathManagement => 'Gerenciamento de caminhos'; + + @override + String get repeater_refresh => 'Atualizar'; + + @override + String get repeater_statusRequestTimeout => 'Solicitação de status expirou.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Erro ao carregar o status: $error'; + } + + @override + String get repeater_systemInformation => 'Informações do Sistema'; + + @override + String get repeater_battery => 'Bateria'; + + @override + String get repeater_clockAtLogin => 'Relógio (no login)'; + + @override + String get repeater_uptime => 'Disponibilidade'; + + @override + String get repeater_queueLength => 'Comprimento da Fila'; + + @override + String get repeater_debugFlags => 'Marcar Flags de Depuração'; + + @override + String get repeater_radioStatistics => 'Estatísticas de Rádio'; + + @override + String get repeater_lastRssi => 'Último RSSI'; + + @override + String get repeater_lastSnr => 'Último SNR'; + + @override + String get repeater_noiseFloor => 'Nível de Ruído'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Estatísticas de Pacote'; + + @override + String get repeater_sent => 'Enviado'; + + @override + String get repeater_received => 'Recebido'; + + @override + String get repeater_duplicates => 'Duplicatas'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days dias ${hours}h ${minutes}m ${seconds}s'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Total: $total, Inundação: $flood, Direto: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Total: $total, Inundação: $flood, Direto: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Inundação: $flood, Direto: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Total: $total'; + } + + @override + String get repeater_settingsTitle => 'Configurações do Repetidor'; + + @override + String get repeater_basicSettings => 'Configurações Básicas'; + + @override + String get repeater_repeaterName => 'Nome do Repetidor'; + + @override + String get repeater_repeaterNameHelper => 'Exibir nome para este repetidor'; + + @override + String get repeater_adminPassword => 'Senha de Administrador'; + + @override + String get repeater_adminPasswordHelper => 'Acesso completo de senha'; + + @override + String get repeater_guestPassword => 'Senha de convidado'; + + @override + String get repeater_guestPasswordHelper => + 'Acesso com senha de leitura somente'; + + @override + String get repeater_radioSettings => 'Configurações de Rádio'; + + @override + String get repeater_frequencyMhz => 'Frequência (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Power'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Largura de banda'; + + @override + String get repeater_spreadingFactor => 'Fator de Dispersão'; + + @override + String get repeater_codingRate => 'Taxa de Codificação'; + + @override + String get repeater_locationSettings => 'Configurações de Localização'; + + @override + String get repeater_latitude => 'Latitude'; + + @override + String get repeater_latitudeHelper => 'Graus decimais (por exemplo, 37,7749)'; + + @override + String get repeater_longitude => 'Longitude'; + + @override + String get repeater_longitudeHelper => + 'Graus decimais (por exemplo, -122,4194)'; + + @override + String get repeater_features => 'Recursos'; + + @override + String get repeater_packetForwarding => 'Encaminhamento de Pacotes'; + + @override + String get repeater_packetForwardingSubtitle => + 'Habilitar o repetidor para encaminhar pacotes'; + + @override + String get repeater_guestAccess => 'Acesso de Convidado'; + + @override + String get repeater_guestAccessSubtitle => + 'Permitir acesso de convidado somente leitura'; + + @override + String get repeater_privacyMode => 'Modo de Privacidade'; + + @override + String get repeater_privacyModeSubtitle => + 'Esconder nome/localização em anúncios'; + + @override + String get repeater_advertisementSettings => 'Configurações de Anúncios'; + + @override + String get repeater_localAdvertInterval => 'Intervalo de Anúncio Local'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes minutos'; + } + + @override + String get repeater_floodAdvertInterval => + 'Intervalo de Anúncio de Inundação'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours horas'; + } + + @override + String get repeater_encryptedAdvertInterval => + 'Intervalo de Anúncio Criptografado'; + + @override + String get repeater_dangerZone => 'Zona de Perigo'; + + @override + String get repeater_rebootRepeater => 'Reiniciar Repetidor'; + + @override + String get repeater_rebootRepeaterSubtitle => + 'Reiniciar o dispositivo repetidor'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Tem certeza de que deseja reiniciar este repetidor?'; + + @override + String get repeater_regenerateIdentityKey => 'Gerar Chave de Identidade'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Gerar nova chave pública/privada'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'Isso gerará uma nova identidade para o repetidor. Continuar?'; + + @override + String get repeater_eraseFileSystem => 'Excluir Sistema de Arquivos'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Formatar o sistema de arquivos do repetidor'; + + @override + String get repeater_eraseFileSystemConfirm => + 'AVISO: Isso apagará todos os dados no repetidor. Isso não pode ser desfeito!'; + + @override + String get repeater_eraseSerialOnly => + 'Apagar está disponível apenas via console serial.'; + + @override + String repeater_commandSent(String command) { + return 'Comando enviado: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Erro ao enviar comando: $error'; + } + + @override + String get repeater_confirm => 'Confirmar'; + + @override + String get repeater_settingsSaved => 'Configurações salvas com sucesso'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Erro ao salvar as configurações: $error'; + } + + @override + String get repeater_refreshBasicSettings => 'Atualizar Configurações Básicas'; + + @override + String get repeater_refreshRadioSettings => + 'Atualizar Configurações de Rádio'; + + @override + String get repeater_refreshTxPower => 'Atualizar TX de energia'; + + @override + String get repeater_refreshLocationSettings => + 'Atualizar Configurações de Localização'; + + @override + String get repeater_refreshPacketForwarding => + 'Atualizar Roteamento de Pacotes'; + + @override + String get repeater_refreshGuestAccess => 'Atualizar Acesso de Convidados'; + + @override + String get repeater_refreshPrivacyMode => 'Atualizar Modo Privacidade'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Atualizar Configurações do Anúncio'; + + @override + String repeater_refreshed(String label) { + return '$label atualizado'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Erro ao atualizar $label'; + } + + @override + String get repeater_cliTitle => 'Repetidor CLI'; + + @override + String get repeater_debugNextCommand => 'Depurar Próximo Comando'; + + @override + String get repeater_commandHelp => 'Ajuda'; + + @override + String get repeater_clearHistory => 'Limpar Histórico'; + + @override + String get repeater_noCommandsSent => 'Ainda não foram enviadas comandos.'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Digite um comando abaixo ou use comandos rápidos'; + + @override + String get repeater_enterCommandHint => 'Insira o comando...'; + + @override + String get repeater_previousCommand => 'Comando anterior'; + + @override + String get repeater_nextCommand => 'Próxima ação'; + + @override + String get repeater_enterCommandFirst => 'Insira um comando primeiro'; + + @override + String get repeater_cliCommandFrameTitle => 'Frame de Comando CLI'; + + @override + String repeater_cliCommandError(String error) { + return 'Erro: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Obter Nome'; + + @override + String get repeater_cliQuickGetRadio => 'Obter Rádio'; + + @override + String get repeater_cliQuickGetTx => 'Obter TX'; + + @override + String get repeater_cliQuickNeighbors => 'Vizinhos'; + + @override + String get repeater_cliQuickVersion => 'Versão'; + + @override + String get repeater_cliQuickAdvertise => 'Anunciar'; + + @override + String get repeater_cliQuickClock => 'Relógio'; + + @override + String get repeater_cliHelpAdvert => 'Envia um pacote de anúncios'; + + @override + String get repeater_cliHelpReboot => + 'Reinicia o dispositivo. (note, você pode obter \'Timeout\' que é normal)'; + + @override + String get repeater_cliHelpClock => + 'Exibe a hora atual de cada dispositivo, de acordo com o relógio do dispositivo.'; + + @override + String get repeater_cliHelpPassword => + 'Define uma nova senha de administrador para o dispositivo.'; + + @override + String get repeater_cliHelpVersion => + 'Mostra a versão do dispositivo e a data de construção do firmware.'; + + @override + String get repeater_cliHelpClearStats => + 'Reseta vários contadores de estatísticas para zero.'; + + @override + String get repeater_cliHelpSetAf => 'Define o fator de tempo de ar.'; + + @override + String get repeater_cliHelpSetTx => + 'Define a potência de transmissão LoRa em dBm (redefinir para aplicar).'; + + @override + String get repeater_cliHelpSetRepeat => + 'Habilita ou desabilita o papel do repetidor para este nó.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Servidor de sala) Se \'ligado\', então o login com senha em branco será permitido, mas não poderá Postar na sala. (apenas ler).'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Define o número máximo de saltos de pacotes de inundação de entrada (se for >= máximo, o pacote não é encaminhado)'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Define o Limite de Interferência (em dB). O valor padrão é 14. Defina como 0 para desativar a detecção de interferência de canal.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Define o intervalo para resetar o Controlador de Ganho Automático. Defina como 0 para desativar.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Habilita ou desabilita a funcionalidade de \"double ACKs\".'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Define o intervalo do timer em minutos para enviar um pacote de anúncio local (sem salto). Defina como 0 para desativar.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Define o intervalo do timer em horas para enviar um pacote de anúncio em massa. Defina como 0 para desativar.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Define/atualiza a senha do convidado. (para repetidores, os logins de convidados podem enviar a solicitação \"Obter Estatísticas\")'; + + @override + String get repeater_cliHelpSetName => 'Define o nome do anúncio.'; + + @override + String get repeater_cliHelpSetLat => + 'Define a latitude do mapa de anúncios. (graus decimais)'; + + @override + String get repeater_cliHelpSetLon => + 'Define a longitude do mapa de anúncios. (graus decimais)'; + + @override + String get repeater_cliHelpSetRadio => + 'Define completamente novos parâmetros de rádio e salva nas preferências. Requer um comando \"reboot\" para aplicar.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Configurações (experimental) base (deve ser > 1 para efeito) para aplicar um pequeno atraso aos pacotes recebidos, com base na força do sinal/pontuação. Defina como 0 para desativar.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Define um fator multiplicado com o tempo-em-ar para um pacote de modo de inundação e com um sistema de slot aleatório, para atrasar seu encaminhamento. (para diminuir a probabilidade de colisões)'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Igual a txdelay, mas para aplicar um atraso aleatório à encaminhamento de pacotes em modo direto.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => 'Ativar/Desativar ponte.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Definir atraso antes de retransmitir pacotes.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Escolha se a ponte retransmitirá pacotes recebidos ou pacotes transmitidos.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Definir a taxa de baud para as pontes rs232.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Definir segredo de ponte para pontes espnow.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Define um fator personalizado para ajustar a voltagem de bateria relatada (apenas suportado em placas selecionadas).'; + + @override + String get repeater_cliHelpTempRadio => + 'Define parâmetros de rádio temporários para o número especificado de minutos, revertendo para os parâmetros de rádio originais posteriormente. (não salva nas preferências).'; + + @override + String get repeater_cliHelpSetPerm => + 'Modifica o ACL. Remove a entrada correspondente (pelo prefixo de pubkey) se \"permissions\" for zero. Adiciona uma nova entrada se o pubkey-hex for de comprimento total e não estiver atualmente no ACL. Atualiza a entrada por correspondência de prefixo de pubkey. Os bits de permissão variam conforme o papel do firmware, mas os 2 bits inferiores são: 0 (Guest), 1 (Read only), 2 (Read write), 3 (Admin)'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Obtém tipo de ponte nenhum, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => + 'Inicia o registro de pacotes no sistema de arquivos.'; + + @override + String get repeater_cliHelpLogStop => + 'Para interromper o registro de pacotes no sistema de arquivos.'; + + @override + String get repeater_cliHelpLogErase => + 'Apaga os logs do pacote do sistema de arquivos.'; + + @override + String get repeater_cliHelpNeighbors => + 'Mostra uma lista de outros nós de repetição ouvidos através de anúncios zero-hop. Cada linha é id-prefixo-hexadecimal:timestamp:snr-vezes-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Remove a primeira entrada correspondente (por prefixo de chave pública (hexadecimal)) da lista de vizinhos.'; + + @override + String get repeater_cliHelpRegion => + '(série apenas) Lista todas as regiões definidas e as permissões de inundação atuais.'; + + @override + String get repeater_cliHelpRegionLoad => + 'NOTA: isto é uma invocação multi-comando especial. Cada comando subsequente é um nome de região (indentado com espaços para indicar a hierarquia pai, com um espaço mínimo). Terminado enviando uma linha em branco/comando.'; + + @override + String get repeater_cliHelpRegionGet => + 'Procura região com o prefixo de nome dado (ou \"\\\" para o âmbito global). Responde com \"-> nome-região (nome-pai) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Adiciona ou atualiza uma definição de região com o nome fornecido.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Remove uma definição de região com o nome fornecido. (deve corresponder exatamente e não ter regiões filhas)'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Define a permissão de \'F\'luido para a região especificada. (\'\' para o escopo global/legado)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Remove a permissão de \"F\"luido para a região especificada. (NOTA: neste momento NÃO é aconselhável usar isso no escopo global/legado!!)'; + + @override + String get repeater_cliHelpRegionHome => + 'Responde com a região \'home\' atual. (Observação aplicada em nenhum lugar ainda, reservado para o futuro)'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Define a região \'casa\'.'; + + @override + String get repeater_cliHelpRegionSave => + 'Persiste a lista/mapa de regiões para o armazenamento.'; + + @override + String get repeater_cliHelpGps => + 'Mostra o status do GPS. Quando o GPS estiver desligado, responde apenas com \"off\", se estiver ligado, responde com \"on\", status, fix, contagem de satélites.'; + + @override + String get repeater_cliHelpGpsOnOff => 'Alterna o estado de energia do GPS.'; + + @override + String get repeater_cliHelpGpsSync => + 'Sincroniza o tempo do nó com o relógio GPS.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Define a posição do nó para coordenadas GPS e salvar preferências.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Define a configuração de anúncio da localização do nó:\n- nenhum: não incluir a localização nos anúncios\n- compartilhar: compartilhar a localização GPS (do SensorManager)\n- preferências: anunciar a localização armazenada nas preferências'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Define a configuração do anúncio de localização.'; + + @override + String get repeater_commandsListTitle => 'Lista de Comandos'; + + @override + String get repeater_commandsListNote => + 'NOTA: para os diversos comandos \"set...\", também existe um comando \"get...\".'; + + @override + String get repeater_general => 'Geral'; + + @override + String get repeater_settingsCategory => 'Configurações'; + + @override + String get repeater_bridge => 'Ponte'; + + @override + String get repeater_logging => 'Registrar'; + + @override + String get repeater_neighborsRepeaterOnly => 'Vizinhos (apenas repetidor)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Gerenciamento de Região (Apenas Repetidor)'; + + @override + String get repeater_regionNote => + 'Os comandos de região foram introduzidos para gerenciar definições e permissões de região.'; + + @override + String get repeater_gpsManagement => 'Gerenciamento GPS'; + + @override + String get repeater_gpsNote => + 'O comando GPS foi introduzido para gerenciar tópicos relacionados à localização.'; + + @override + String get telemetry_receivedData => 'Dados de Telemetria Recebidos'; + + @override + String get telemetry_requestTimeout => + 'Solicitação de telemetria expirou o tempo.'; + + @override + String telemetry_errorLoading(String error) { + return 'Erro ao carregar a telemetria: $error'; + } + + @override + String get telemetry_noData => 'Não estão disponíveis dados de telemetria.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Canal $channel'; + } + + @override + String get telemetry_batteryLabel => 'Bateria'; + + @override + String get telemetry_voltageLabel => 'Tensão'; + + @override + String get telemetry_mcuTemperatureLabel => 'Temperatura do MCU'; + + @override + String get telemetry_temperatureLabel => 'Temperatura'; + + @override + String get telemetry_currentLabel => 'Atual'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Rótulo de Caminho de Pacote'; + + @override + String get channelPath_viewMap => 'Ver mapa'; + + @override + String get channelPath_otherObservedPaths => 'Outros Caminhos Observados'; + + @override + String get channelPath_repeaterHops => 'Saltos do Repetidor'; + + @override + String get channelPath_noHopDetails => + 'Os detalhes do pacote não estão disponíveis.'; + + @override + String get channelPath_messageDetails => 'Detalhes da Mensagem'; + + @override + String get channelPath_senderLabel => 'Remetente'; + + @override + String get channelPath_timeLabel => 'Tempo'; + + @override + String get channelPath_repeatsLabel => 'Repete'; + + @override + String channelPath_pathLabel(int index) { + return 'Caminho $index'; + } + + @override + String get channelPath_observedLabel => 'Observado'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Rastreamento observado $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'Não há dados de localização.'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Desconhecido'; + + @override + String get channelPath_floodPath => 'Inundação'; + + @override + String get channelPath_directPath => 'Salvar'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 de $total saltos'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed de $total saltos'; + } + + @override + String get channelPath_mapTitle => 'Mapa de Caminhos'; + + @override + String get channelPath_noRepeaterLocations => + 'Não estão disponíveis localizações de repetidores para este caminho.'; + + @override + String channelPath_primaryPath(int index) { + return 'Caminho $index (Primário)'; + } + + @override + String get channelPath_pathLabelTitle => 'Caminho'; + + @override + String get channelPath_observedPathHeader => 'Rastreamento Observado'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'Não estão disponíveis detalhes de voo para este pacote.'; + + @override + String get channelPath_unknownRepeater => 'Repetidor Desconhecido'; + + @override + String get listFilter_tooltip => 'Filtrar e ordenar'; + + @override + String get listFilter_sortBy => 'Ordenar por'; + + @override + String get listFilter_latestMessages => 'Últimas mensagens'; + + @override + String get listFilter_heardRecently => 'Ouvido recentemente'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Filtros'; + + @override + String get listFilter_all => 'Tudo'; + + @override + String get listFilter_users => 'Usuários'; + + @override + String get listFilter_repeaters => 'Repetidores'; + + @override + String get listFilter_roomServers => 'Servidores de sala'; + + @override + String get listFilter_unreadOnly => 'Apenas não lido'; + + @override + String get listFilter_newGroup => 'Novo grupo'; +} diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart new file mode 100644 index 0000000..e9eb10c --- /dev/null +++ b/lib/l10n/app_localizations_sk.dart @@ -0,0 +1,2378 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Slovak (`sk`). +class AppLocalizationsSk extends AppLocalizations { + AppLocalizationsSk([String locale = 'sk']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Kontakty'; + + @override + String get nav_channels => 'Kanály'; + + @override + String get nav_map => 'Mapa'; + + @override + String get common_cancel => 'Zrušiť'; + + @override + String get common_connect => 'Pripojiť'; + + @override + String get common_unknownDevice => 'Neznáme zariadenie'; + + @override + String get common_save => 'Uložiť'; + + @override + String get common_delete => 'Odstrániť'; + + @override + String get common_close => 'Zavrieť'; + + @override + String get common_edit => 'Upraviť'; + + @override + String get common_add => 'Pridať'; + + @override + String get common_settings => 'Nastavenia'; + + @override + String get common_disconnect => 'Odpojiť'; + + @override + String get common_connected => 'Pripojené'; + + @override + String get common_disconnected => 'Odpojené'; + + @override + String get common_create => 'Vytvoriť'; + + @override + String get common_continue => 'Pokračovať'; + + @override + String get common_share => 'Zdieľať'; + + @override + String get common_copy => 'Kopírovať'; + + @override + String get common_retry => 'Pokusť znova'; + + @override + String get common_hide => 'Skryť'; + + @override + String get common_remove => 'Odstrániť'; + + @override + String get common_enable => 'Povolit'; + + @override + String get common_disable => 'Zakázať'; + + @override + String get common_reboot => 'Restartovať'; + + @override + String get common_loading => 'Načítavanie...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Skrívania zariadení...'; + + @override + String get scanner_connecting => 'Pripojujem sa...'; + + @override + String get scanner_disconnecting => 'Odpojuje sa...'; + + @override + String get scanner_notConnected => 'Nezriadené'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Pripojené k $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Hľadám zariadenia MeshCore...'; + + @override + String get scanner_tapToScan => + 'Stlač skenovanie na nájdenie zariadení MeshCore.'; + + @override + String scanner_connectionFailed(String error) { + return 'Pripojenie zlyhalo: $error'; + } + + @override + String get scanner_stop => 'Zastavte'; + + @override + String get scanner_scan => 'Skončiť'; + + @override + String get device_quickSwitch => 'Rýchle prepínač'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Nastavenia'; + + @override + String get settings_deviceInfo => 'Informácie o zariadení'; + + @override + String get settings_appSettings => 'Nastavenia aplikácie'; + + @override + String get settings_appSettingsSubtitle => + 'Upozornenia, správy a nastavenia mapy'; + + @override + String get settings_nodeSettings => 'Nastavenia uzla'; + + @override + String get settings_nodeName => 'Názov uzla'; + + @override + String get settings_nodeNameNotSet => 'Nezriadené'; + + @override + String get settings_nodeNameHint => 'Zadajte názov uzla'; + + @override + String get settings_nodeNameUpdated => 'Meno aktualizované'; + + @override + String get settings_radioSettings => 'Nastavenia rádia'; + + @override + String get settings_radioSettingsSubtitle => + 'Frekvencia, výkon, rozptylovací faktor'; + + @override + String get settings_radioSettingsUpdated => 'Nastavenia rádia aktualizované'; + + @override + String get settings_location => 'Lokalita'; + + @override + String get settings_locationSubtitle => 'GPS súradnice'; + + @override + String get settings_locationUpdated => 'Lokalita aktualizovaná'; + + @override + String get settings_locationBothRequired => + 'Zadajte obidve zložky zemyslenia a zložky meracieho kruhu.'; + + @override + String get settings_locationInvalid => 'Neplatná šírka alebo dĺžka.'; + + @override + String get settings_latitude => 'Súradnica'; + + @override + String get settings_longitude => 'Dĺžka'; + + @override + String get settings_privacyMode => 'Režim ochrany súkromia'; + + @override + String get settings_privacyModeSubtitle => 'Skryť meno/poloha v reklamách'; + + @override + String get settings_privacyModeToggle => + 'Prepínač súkromného režimu skryje vaše meno a polohu v reklamách.'; + + @override + String get settings_privacyModeEnabled => 'Ochranný režim je povolený.'; + + @override + String get settings_privacyModeDisabled => 'Ochranný režim je vypnutý'; + + @override + String get settings_actions => 'Možné akcie'; + + @override + String get settings_sendAdvertisement => 'Odoslať reklamu'; + + @override + String get settings_sendAdvertisementSubtitle => 'Momentálne priezornejšie.'; + + @override + String get settings_advertisementSent => 'Reklama odeslaná'; + + @override + String get settings_syncTime => 'Čas synchronizácie'; + + @override + String get settings_syncTimeSubtitle => + 'Nastaviť hodiny zariadenia na čas telefónu'; + + @override + String get settings_timeSynchronized => 'Čas synchronizovaný'; + + @override + String get settings_refreshContacts => 'Načítať Kontakty'; + + @override + String get settings_refreshContactsSubtitle => + 'Načítať zoznam kontaktov z zariadenia'; + + @override + String get settings_rebootDevice => 'Restartovať zariadenie'; + + @override + String get settings_rebootDeviceSubtitle => + 'Restartujte zariadenie MeshCore.'; + + @override + String get settings_rebootDeviceConfirm => + 'Ste si istý, že chcete zariadenie reštartovať? Budete odpojení.'; + + @override + String get settings_debug => 'Ladenie'; + + @override + String get settings_bleDebugLog => 'Log BLE Debug'; + + @override + String get settings_bleDebugLogSubtitle => + 'Príkazy BLE, odpovede a surové dáta'; + + @override + String get settings_appDebugLog => 'Záznam ladenia aplikácie'; + + @override + String get settings_appDebugLogSubtitle => 'Správy z ladenia aplikácie'; + + @override + String get settings_about => 'O nás'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => 'MeshCore Open Source Projekt 2024'; + + @override + String get settings_aboutDescription => + 'Otvorený zdrojový Flutter klient pre MeshCore LoRa sieťové zariadenia.'; + + @override + String get settings_infoName => 'Meno'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'Status'; + + @override + String get settings_infoBattery => 'Batéria'; + + @override + String get settings_infoPublicKey => 'Verejný kľúč'; + + @override + String get settings_infoContactsCount => 'Počet kontaktov'; + + @override + String get settings_infoChannelCount => 'Počet kanálov'; + + @override + String get settings_presets => 'Prednastavenia'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Frekvencia (MHz)'; + + @override + String get settings_frequencyHelper => '300,0 – 2500,0'; + + @override + String get settings_frequencyInvalid => 'Neplatná frekvencia (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Šírka pásma'; + + @override + String get settings_spreadingFactor => 'Rozptýľovací faktor'; + + @override + String get settings_codingRate => 'Cenový kurz pre programovanie'; + + @override + String get settings_txPower => 'TX Výkon (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Neplatná hodnota výkonu TX (0-22 dBm)'; + + @override + String get settings_longRange => 'Dlhý dosah'; + + @override + String get settings_fastSpeed => 'Rýchla rýchlosť'; + + @override + String settings_error(String message) { + return 'Chyba: $message'; + } + + @override + String get appSettings_title => 'Nastavenia aplikácie'; + + @override + String get appSettings_appearance => 'Vzhľad'; + + @override + String get appSettings_theme => 'Téma'; + + @override + String get appSettings_themeSystem => 'Predvolený systém'; + + @override + String get appSettings_themeLight => 'Svetlo'; + + @override + String get appSettings_themeDark => 'Tmavé'; + + @override + String get appSettings_language => 'Jazyk'; + + @override + String get appSettings_languageSystem => 'Predvolený systém'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Upozornenia'; + + @override + String get appSettings_enableNotifications => 'Povolte Notifikácie'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Zísť o upozornenia na správy a inzeráty'; + + @override + String get appSettings_notificationPermissionDenied => + 'Odmietená povolenie notifikácií'; + + @override + String get appSettings_notificationsEnabled => 'Upozornenia povolené'; + + @override + String get appSettings_notificationsDisabled => 'Upozornenia sú vypnuté'; + + @override + String get appSettings_messageNotifications => 'Správy od upozornení'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Zobraziť upozornenie pri prijímaní nových správ'; + + @override + String get appSettings_channelMessageNotifications => 'Notifikácie z kanálov'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Zobraziť upozornenie pri prijímaní správ z kanálu'; + + @override + String get appSettings_advertisementNotifications => 'Upozornenia na reklamy'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Zobraziť upozornenie, keď sa objavia nové uzly.'; + + @override + String get appSettings_messaging => 'Správy'; + + @override + String get appSettings_clearPathOnMaxRetry => 'Vyčisti cestu na Max Retry'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Resetovať kontaktný priebeh po 5 neúspešných pokusoch o doručenie'; + + @override + String get appSettings_pathsWillBeCleared => + 'Cesty budú vymazané po 5 neúspešných pokusoch.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Cesty sa automaticky nevymazávajú.'; + + @override + String get appSettings_autoRouteRotation => 'Automatické prechodové trasy'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Striedajte sa medzi najlepšími trasami a režimom povodňovej analýzy.'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Automatické otáčanie trasy povolené'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Automatické prekladanie trás pozastavené'; + + @override + String get appSettings_battery => 'Batéria'; + + @override + String get appSettings_batteryChemistry => 'Chemická zloženie batérie'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Nastavenie pre $deviceName'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Pripojte sa k zariadeniu na výber'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6–3,65V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + + @override + String get appSettings_mapDisplay => 'Zobrazenie mapy'; + + @override + String get appSettings_showRepeaters => 'Zobraziť opakovače'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Zobraziť opakujúce sa uzly na mape'; + + @override + String get appSettings_showChatNodes => 'Zobraziť uzly chatových správ'; + + @override + String get appSettings_showChatNodesSubtitle => + 'Zobraziť chatové uzly na mape'; + + @override + String get appSettings_showOtherNodes => 'Zobraziť ďalšie uzly'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Zobraziť ostatné typy uzlov na mape'; + + @override + String get appSettings_timeFilter => 'Filtrovacie Časové Obdoby'; + + @override + String get appSettings_timeFilterShowAll => 'Zobraziť všetky uzly'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Zobraziť uzly z posledných $hours hodín'; + } + + @override + String get appSettings_mapTimeFilter => 'Filtračný čas mapy'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Zobraziť uzly objavené v:'; + + @override + String get appSettings_allTime => 'Všetky časy'; + + @override + String get appSettings_lastHour => 'Posledná hodina'; + + @override + String get appSettings_last6Hours => 'Posledné 6 hodín'; + + @override + String get appSettings_last24Hours => 'Posledných 24 hodín'; + + @override + String get appSettings_lastWeek => 'Minul týždeň'; + + @override + String get appSettings_offlineMapCache => 'Offline Mapa Pamäť'; + + @override + String get appSettings_noAreaSelected => 'Neoznačila sa žiadna oblasť'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Vyberená oblasť (zoom $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Ladenie'; + + @override + String get appSettings_appDebugLogging => 'Záznamy ladenia aplikácie'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Logovací správy aplikácie pre ladenie'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'Aplikácia povolila ladenie protokolmi'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'Zabudované ladenie aplikácie je vypnuté.'; + + @override + String get contacts_title => 'Kontakty'; + + @override + String get contacts_noContacts => 'Zatiaľ žiadne kontakty.'; + + @override + String get contacts_contactsWillAppear => + 'Kontakty sa zobrazia, keď zariadenia spúšťajú reklamu.'; + + @override + String get contacts_searchContacts => 'Vyhľadávajte kontakty...'; + + @override + String get contacts_noUnreadContacts => 'Žiadne neprečítané kontakty'; + + @override + String get contacts_noContactsFound => + 'Neboli nájdených žiadnych kontaktov ani skupiny.'; + + @override + String get contacts_deleteContact => 'Odstrániť kontakt'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Odstrániť $contactName z kontaktov?'; + } + + @override + String get contacts_manageRepeater => 'Spravovať opakované zoznamy'; + + @override + String get contacts_roomLogin => 'Prihlásenie do miestnosti'; + + @override + String get contacts_openChat => 'Otvorené Chat'; + + @override + String get contacts_editGroup => 'Upraviť skupinu'; + + @override + String get contacts_deleteGroup => 'Vymažť skupinu'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Odstrániť \"$groupName\"?'; + } + + @override + String get contacts_newGroup => 'Nová skupina'; + + @override + String get contacts_groupName => 'Názov skupiny'; + + @override + String get contacts_groupNameRequired => 'Skupina musí mať názov.'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'Skupina \"$name\" už existuje'; + } + + @override + String get contacts_filterContacts => 'Filtrovať kontakty...'; + + @override + String get contacts_noContactsMatchFilter => + 'Žiadne kontakty neodídu vášmu filtru.'; + + @override + String get contacts_noMembers => 'Žiadni členovia'; + + @override + String get contacts_lastSeenNow => 'Posledné zreteľné zobrazenie teraz'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Posledné zobrazenie $minutes min. dozadu'; + } + + @override + String get contacts_lastSeenHourAgo => + 'Zobral/Zabral poslednýkrát pred hodinou.'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Posledné zobrazenie $hours hodín dozadu'; + } + + @override + String get contacts_lastSeenDayAgo => + 'Zobral/Zabral posledný raz pred 1 dňom.'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Posledné zobrazenie $days dní dozadu'; + } + + @override + String get channels_title => 'Kanály'; + + @override + String get channels_noChannelsConfigured => 'Neobsiahnuté žiadne kanály'; + + @override + String get channels_addPublicChannel => 'Pridať verejný kanál'; + + @override + String get channels_searchChannels => 'Vyhľadávajte kanály...'; + + @override + String get channels_noChannelsFound => 'Neobsiahlo sa žiadnych kanálov.'; + + @override + String channels_channelIndex(int index) { + return 'Kanál $index'; + } + + @override + String get channels_hashtagChannel => 'Kanál s hashtagom'; + + @override + String get channels_public => 'Veľké verejné'; + + @override + String get channels_private => 'Osobné'; + + @override + String get channels_publicChannel => 'Veľké verejne kanály'; + + @override + String get channels_privateChannel => 'Osobné kanál'; + + @override + String get channels_editChannel => 'Upraviť kanál'; + + @override + String get channels_deleteChannel => 'Odstrániť kanál'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Odstrániť \"$name\"? To sa nedá zrušiť.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Kanál \"$name\" bol odstránený'; + } + + @override + String get channels_addChannel => 'Pridať kanál'; + + @override + String get channels_channelIndexLabel => 'Index kanála'; + + @override + String get channels_channelName => 'Názov kanálu'; + + @override + String get channels_usePublicChannel => 'Použite verejný kanál'; + + @override + String get channels_standardPublicPsk => 'Štandardný verejný PSK'; + + @override + String get channels_pskHex => 'PSK (Šifrovacia kľúčik)'; + + @override + String get channels_generateRandomPsk => 'Generovať náhodný PSK'; + + @override + String get channels_enterChannelName => 'Prosím, zadajte názov kanála.'; + + @override + String get channels_pskMustBe32Hex => + 'PSK musí mať 32 hexadecimálových znakov.'; + + @override + String channels_channelAdded(String name) { + return 'Kanál \"$name\" pridaný'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Upraviť kanál $index'; + } + + @override + String get channels_smazCompression => 'Odstránenie kompresie SMAZ'; + + @override + String channels_channelUpdated(String name) { + return 'Kanál \"$name\" bol aktualizovaný'; + } + + @override + String get channels_publicChannelAdded => 'Veľký kanál pridaný'; + + @override + String get channels_sortBy => 'Triediť podľa'; + + @override + String get channels_sortManual => 'Ručne'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => 'Posledné správy'; + + @override + String get channels_sortUnread => 'Nezriadené'; + + @override + String get chat_noMessages => 'Zatiaľ žiadne správy.'; + + @override + String get chat_sendMessageToStart => 'Pošlite správu na začiatok'; + + @override + String get chat_originalMessageNotFound => 'Neznámy pôvodný odkaz.'; + + @override + String chat_replyingTo(String name) { + return 'Odpovedám $name'; + } + + @override + String chat_replyTo(String name) { + return 'Odpovedať $name'; + } + + @override + String get chat_location => 'Lokalita'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Pošli správu $contactName'; + } + + @override + String get chat_typeMessage => 'Napište správu...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Správa je príliš dlhá (max $maxBytes bytov).'; + } + + @override + String get chat_messageCopied => 'Správa skopírovaná'; + + @override + String get chat_messageDeleted => 'Posolstvo odstránené'; + + @override + String get chat_retryingMessage => 'Pokus o obnovenie'; + + @override + String chat_retryCount(int current, int max) { + return 'Skúsiť $current/$max'; + } + + @override + String get chat_sendGif => 'Odoslať GIF'; + + @override + String get chat_reply => 'Odpovedať'; + + @override + String get chat_addReaction => 'Pridať Reakciu'; + + @override + String get chat_me => 'Mne'; + + @override + String get emojiCategorySmileys => 'Emoji'; + + @override + String get emojiCategoryGestures => 'Gestá'; + + @override + String get emojiCategoryHearts => 'Srdcia'; + + @override + String get emojiCategoryObjects => 'Objekty'; + + @override + String get gifPicker_title => 'Vyberte GIF'; + + @override + String get gifPicker_searchHint => 'Vyhľadávajte GIFy...'; + + @override + String get gifPicker_poweredBy => 'Napájané spoločnosťou GIPHY'; + + @override + String get gifPicker_noGifsFound => 'Neboli nájdené žiadne GIFy.'; + + @override + String get gifPicker_failedLoad => 'Nepodarilo sa načítať GIFy'; + + @override + String get gifPicker_failedSearch => 'Nepodarilo sa vyhľadať GIFy'; + + @override + String get gifPicker_noInternet => 'Žiadna internetová konektivita'; + + @override + String get debugLog_appTitle => 'Záznam ladenia aplikácie'; + + @override + String get debugLog_bleTitle => 'Log BLE Debug'; + + @override + String get debugLog_copyLog => 'Kopírovať záznam'; + + @override + String get debugLog_clearLog => 'Vymažať záznam'; + + @override + String get debugLog_copied => 'Záznam ladenia skopírovaný'; + + @override + String get debugLog_bleCopied => 'Kopírovaný záznam z BLE.'; + + @override + String get debugLog_noEntries => + 'Zatiaľ neboli zaznamenané žiadne debug logy.'; + + @override + String get debugLog_enableInSettings => + 'Povolte ladicové logy v nastaveniach'; + + @override + String get debugLog_frames => 'Rámce'; + + @override + String get debugLog_rawLogRx => 'Raw Log-RX'; + + @override + String get debugLog_noBleActivity => 'Zatiaľ žiadna aktivita BLE.'; + + @override + String debugFrame_length(int count) { + return 'Dĺžka rámca: $count bajtov'; + } + + @override + String debugFrame_command(String value) { + return 'Prikáž: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Textová zvesť:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Cieľový PubKey: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Časové označenie: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Žiadne vlajky: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Typ textu: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Jednoduché'; + + @override + String debugFrame_text(String text) { + return '- Text: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Hex Dump:'; + + @override + String get chat_pathManagement => 'Správa ciest'; + + @override + String get chat_routingMode => 'Režim trasy'; + + @override + String get chat_autoUseSavedPath => 'Použiť uloženú cestu'; + + @override + String get chat_forceFloodMode => + 'Zavrieť režim núdzového povodňového režimu'; + + @override + String get chat_recentAckPaths => 'Nedávne cesty ACK (klepni na použitie):'; + + @override + String get chat_pathHistoryFull => + 'História ciest je plná. Odstráňte záznamy, aby ste mohli pridať nové.'; + + @override + String get chat_hopSingular => 'Skok'; + + @override + String get chat_hopPlural => 'Skákať'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'Úspechy'; + + @override + String get chat_removePath => 'Odstrániť cestu'; + + @override + String get chat_noPathHistoryYet => + 'Zatiaľ žiadna história trás.\nPošlite správu a objavte trasy.'; + + @override + String get chat_pathActions => 'Cesty:'; + + @override + String get chat_setCustomPath => 'Nastaviť vlastnú cestu'; + + @override + String get chat_setCustomPathSubtitle => 'Ručne zadajte trasu.'; + + @override + String get chat_clearPath => 'Vyčistiš cestu'; + + @override + String get chat_clearPathSubtitle => + 'Znovu nájsť vynútene pri nasledujacej pošlite'; + + @override + String get chat_pathCleared => + 'Cesta vyčistená. Nasledujúce prepočetné získa trasu znova.'; + + @override + String get chat_floodModeSubtitle => + 'Použite prepínanie trasy v navigačnom paneli.'; + + @override + String get chat_floodModeEnabled => + 'Odosporňovacia prevádzka je zapnutá. Vypnite ju znova cez ikonu routovania v navigačnom páse.'; + + @override + String get chat_fullPath => 'Celá cesta'; + + @override + String get chat_pathDetailsNotAvailable => + 'Podrobnosti o ceste zatiaľ dostupné nie sú. Skúste poslať správu na obnovenie.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Cesta nastavená: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Uložené lokálne. Spojte sa na synchronizáciu.'; + + @override + String get chat_pathDeviceConfirmed => 'Zariadenie potvrdené.'; + + @override + String get chat_pathDeviceNotConfirmed => + 'Zariadenie zatiaľ nebolo potvrdené.'; + + @override + String get chat_type => 'Napište'; + + @override + String get chat_path => 'Cesta'; + + @override + String get chat_publicKey => 'Verejný kľúč'; + + @override + String get chat_compressOutgoingMessages => 'Komprimovať odoslané správy'; + + @override + String get chat_floodForced => 'Povodňová (nutená)'; + + @override + String get chat_directForced => 'Priame (donútené)'; + + @override + String chat_hopsForced(int count) { + return '$count skokov (nutené)'; + } + + @override + String get chat_floodAuto => 'Povod (automaticky)'; + + @override + String get chat_direct => 'Priamo'; + + @override + String get chat_poiShared => 'Zdieľané body záujmu'; + + @override + String chat_unread(int count) { + return 'Nezriadené: $count'; + } + + @override + String get map_title => 'Mapa uzlov'; + + @override + String get map_noNodesWithLocation => 'Žiadne uzly s údajmi o polohe'; + + @override + String get map_nodesNeedGps => + 'Uholníky musia zdieľať svoje GPS súradnice, aby sa zobrazili na mape.'; + + @override + String map_nodesCount(int count) { + return 'Uzly: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Krúžky: $count'; + } + + @override + String get map_chat => 'Rozhovor'; + + @override + String get map_repeater => 'Opakovanie'; + + @override + String get map_room => 'Izba'; + + @override + String get map_sensor => 'Senzor'; + + @override + String get map_pinDm => 'Zabudka (DM)'; + + @override + String get map_pinPrivate => 'Zabudka (Osobná)'; + + @override + String get map_pinPublic => 'Zablokovať (verejne)'; + + @override + String get map_lastSeen => 'Posledné zreteľné zobrazenie'; + + @override + String get map_disconnectConfirm => + 'Ste si istý/á, že chcete odpojiť od tohto zariadenia?'; + + @override + String get map_from => 'Od'; + + @override + String get map_source => 'Zdroj'; + + @override + String get map_flags => 'Zástavy'; + + @override + String get map_shareMarkerHere => 'Zdieľte značku tu'; + + @override + String get map_pinLabel => 'Označka upozornenia'; + + @override + String get map_label => 'Značka'; + + @override + String get map_pointOfInterest => 'Bod záujmu'; + + @override + String get map_sendToContact => 'Pošleť na kontakt'; + + @override + String get map_sendToChannel => 'Poslať do kanálu'; + + @override + String get map_noChannelsAvailable => 'Неexistujú žiadne kanály.'; + + @override + String get map_publicLocationShare => 'Zdieľiť verejnú lokalitu'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'Čoskoro budete zdieľať polohu v $channelLabel. Tento kanál je verejný a môže ho vidieť každý s PSK.'; + } + + @override + String get map_connectToShareMarkers => + 'Pripojte sa k zariadeniu na zdieľanie značiek'; + + @override + String get map_filterNodes => 'Filtrovať uzly'; + + @override + String get map_nodeTypes => 'Typy uzlov'; + + @override + String get map_chatNodes => 'Chatové uzly'; + + @override + String get map_repeaters => 'Opakovadlá'; + + @override + String get map_otherNodes => 'Ostatné uzly'; + + @override + String get map_keyPrefix => 'Päťciferné predpona'; + + @override + String get map_filterByKeyPrefix => 'Filtrovať podľa predponového kľúča'; + + @override + String get map_publicKeyPrefix => 'Prefix verejného kľúča'; + + @override + String get map_markers => 'Označkovače'; + + @override + String get map_showSharedMarkers => 'Zobraziť zdieľané značky'; + + @override + String get map_lastSeenTime => 'Posledný čas sledovania'; + + @override + String get map_sharedPin => 'Zdieľaný PIN'; + + @override + String get map_joinRoom => 'Pripojiť miestnosť'; + + @override + String get map_manageRepeater => 'Spravovať Opakovanie'; + + @override + String get mapCache_title => 'Offline Mapa Pamäť'; + + @override + String get mapCache_selectAreaFirst => 'Vyberte si oblasť na predprerúčenie.'; + + @override + String get mapCache_noTilesToDownload => + 'Žiadne dlaždice na stiahnutie pre toto zóna'; + + @override + String get mapCache_downloadTilesTitle => 'Stiahnuť dlaždice'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Stiahnuť $count dlaždíc na offline použitie?'; + } + + @override + String get mapCache_downloadAction => 'Stiahnuť'; + + @override + String mapCache_cachedTiles(int count) { + return 'Zabudené $count dlaždíc'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Uložené $downloaded dlaždice ($failed neúspešné)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => 'Vymazať offline uloženie'; + + @override + String get mapCache_clearOfflineCachePrompt => + 'Odstrániť všetky uložené mapové dlaždice?'; + + @override + String get mapCache_offlineCacheCleared => 'Offline polia vymazaná'; + + @override + String get mapCache_noAreaSelected => 'Neoznačila sa žiadna oblasť'; + + @override + String get mapCache_cacheArea => 'Obdĺžková oblasť'; + + @override + String get mapCache_useCurrentView => 'Použite aktuálny zobrazenie'; + + @override + String get mapCache_zoomRange => 'Rozsah zväčšenia'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Odhadnuté dlaždice: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Stiahnuté $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Stiahnuť dlaždice'; + + @override + String get mapCache_clearCacheButton => 'Vyprázdniť Vädsť'; + + @override + String mapCache_failedDownloads(int count) { + return 'Neúspešné stiahnutia: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Príbeh'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes min dozadu'; + } + + @override + String time_hoursAgo(int hours) { + return '$hours h dozadu'; + } + + @override + String time_daysAgo(int days) { + return '$days dní dozadu'; + } + + @override + String get time_hour => 'hodina'; + + @override + String get time_hours => 'hodiny'; + + @override + String get time_day => 'deň'; + + @override + String get time_days => 'dni'; + + @override + String get time_week => 'týždeň'; + + @override + String get time_weeks => 'týždne'; + + @override + String get time_month => 'mesiac'; + + @override + String get time_months => 'mesiace'; + + @override + String get time_minutes => 'minúty'; + + @override + String get time_allTime => 'Všetko Časom'; + + @override + String get dialog_disconnect => 'Odpojiť'; + + @override + String get dialog_disconnectConfirm => + 'Ste si istý/á, že chcete odpojiť od tohto zariadenia?'; + + @override + String get login_repeaterLogin => 'Opätovné prihlásenie'; + + @override + String get login_roomLogin => 'Prihlásenie do miestnosti'; + + @override + String get login_password => 'Heslo'; + + @override + String get login_enterPassword => 'Zadajte heslo'; + + @override + String get login_savePassword => 'Uložiť heslo'; + + @override + String get login_savePasswordSubtitle => + 'Heslo bude bezpečne uložené na tomto zariadení.'; + + @override + String get login_repeaterDescription => + 'Zadajte heslo opakovača, aby ste získali prístup k nastaveniam a stavu.'; + + @override + String get login_roomDescription => + 'Zadajte heslo do miestnosti na prístup k nastaveniam a stavu.'; + + @override + String get login_routing => 'Rútiace'; + + @override + String get login_routingMode => 'Režim trasy'; + + @override + String get login_autoUseSavedPath => 'Použiť uloženú cestu'; + + @override + String get login_forceFloodMode => + 'Zavrieť režim núdzového povodňového režimu'; + + @override + String get login_managePaths => 'Spravovať Cesty'; + + @override + String get login_login => 'Prihlásiť'; + + @override + String login_attempt(int current, int max) { + return 'Skúšaj $current/$max'; + } + + @override + String login_failed(String error) { + return 'Prihlásenie zlyhalo: $error'; + } + + @override + String get common_reload => 'Načítať'; + + @override + String get common_clear => 'Zmazať'; + + @override + String path_currentPath(String path) { + return 'Aktívna cesta: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Používa $count $_temp0 cestu'; + } + + @override + String get path_enterCustomPath => 'Zadajte vlastný priebeh'; + + @override + String get path_currentPathLabel => 'Aktuálny priebeh'; + + @override + String get path_hexPrefixInstructions => + 'Zadajte 2-miestne hexové predpony pre každú fázu, oddelené čiarkami.'; + + @override + String get path_hexPrefixExample => + 'A1,F2,3C (každý uzel používa prvý bajt svojho verejného kľúča)'; + + @override + String get path_labelHexPrefixes => 'Cesty (hexové predpony)'; + + @override + String get path_helperMaxHops => + 'Max 64 skokov. Každý prefix je 2 hexadecimálne znaky (1 bajt).'; + + @override + String get path_selectFromContacts => 'Vyberte sa z kontaktov:'; + + @override + String get path_noRepeatersFound => + 'Nenašli sa žiadne opakovače ani serverové miestnosti.'; + + @override + String get path_customPathsRequire => + 'Vlastné cesty vyžadujú medziletoch, ktoré môžu prenášať správky.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Neplatné hexové predpony: $prefixes'; + } + + @override + String get path_tooLong => + 'Cesta je príliš dlhá. Umožnené je maximum 64 skokov.'; + + @override + String get path_setPath => 'Nastaviť cestu'; + + @override + String get repeater_management => 'Správa opakérov'; + + @override + String get repeater_managementTools => 'Nástroje na správu'; + + @override + String get repeater_status => 'Status'; + + @override + String get repeater_statusSubtitle => + 'Zobraziť stav, štatistiky a susedov repeatera'; + + @override + String get repeater_telemetry => 'Telemetria'; + + @override + String get repeater_telemetrySubtitle => + 'Zobraziť telemetriu senzorov a systémových štatistík'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Pošlite príkazy opakovaču'; + + @override + String get repeater_settings => 'Nastavenia'; + + @override + String get repeater_settingsSubtitle => 'Konfigurujte parametre opakovača'; + + @override + String get repeater_statusTitle => 'Status opakého zboru'; + + @override + String get repeater_routingMode => 'Režim trasy'; + + @override + String get repeater_autoUseSavedPath => 'Použiť uloženú cestu'; + + @override + String get repeater_forceFloodMode => + 'Zavrieť režim núdzového povodňového režimu'; + + @override + String get repeater_pathManagement => 'Správa trás'; + + @override + String get repeater_refresh => 'Obnoviť'; + + @override + String get repeater_statusRequestTimeout => 'Požiadavka stavu zlyhala.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Chyba pri načítaní stavu: $error'; + } + + @override + String get repeater_systemInformation => 'Informácie o systéme'; + + @override + String get repeater_battery => 'Batéria'; + + @override + String get repeater_clockAtLogin => 'Čas (při přihlášení)'; + + @override + String get repeater_uptime => 'Dostupnosť'; + + @override + String get repeater_queueLength => 'Dĺžka fronty'; + + @override + String get repeater_debugFlags => 'Kontrolné značky'; + + @override + String get repeater_radioStatistics => 'Rádio Štatistiky'; + + @override + String get repeater_lastRssi => 'Posledná RSSI'; + + @override + String get repeater_lastSnr => 'Posledný SNR'; + + @override + String get repeater_noiseFloor => 'Hladina šumu'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Statistiky balíka'; + + @override + String get repeater_sent => 'Odoslané'; + + @override + String get repeater_received => 'Prišlo'; + + @override + String get repeater_duplicates => 'Duplikáty'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days dní ${hours}h ${minutes}m ${seconds}s'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Celkem: $total, Povodňový režim: $flood, Priamy: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Celkem: $total, Povodňový režim: $flood, Priamy: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Pond: $flood, Priamy: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Celkem: $total'; + } + + @override + String get repeater_settingsTitle => 'Nastavenia Opakovača'; + + @override + String get repeater_basicSettings => 'Základné nastavenia'; + + @override + String get repeater_repeaterName => 'Opakovacia názov'; + + @override + String get repeater_repeaterNameHelper => 'Zobrazenie názvu tohto opakovača'; + + @override + String get repeater_adminPassword => 'Heslo administrátora'; + + @override + String get repeater_adminPasswordHelper => 'Celý prístupový heslo'; + + @override + String get repeater_guestPassword => 'Heslo hosťa'; + + @override + String get repeater_guestPasswordHelper => 'Prístupový heslo iba na čítanie'; + + @override + String get repeater_radioSettings => 'Nastavenia rádia'; + + @override + String get repeater_frequencyMhz => 'Frekvencia (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Power'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Šírka pásma'; + + @override + String get repeater_spreadingFactor => 'Šírenie faktoru'; + + @override + String get repeater_codingRate => 'Rýchlosť kódovania'; + + @override + String get repeater_locationSettings => 'Nastavenia polohy'; + + @override + String get repeater_latitude => 'Súradnica'; + + @override + String get repeater_latitudeHelper => 'Desatinné zložky (napr. 37.7749)'; + + @override + String get repeater_longitude => 'Dĺžka'; + + @override + String get repeater_longitudeHelper => 'Desatinné zložky (napr. -122.4194)'; + + @override + String get repeater_features => 'Funkcie'; + + @override + String get repeater_packetForwarding => 'Riadenie prienikov'; + + @override + String get repeater_packetForwardingSubtitle => + 'Povolte opakovač na smerovanie paketov.'; + + @override + String get repeater_guestAccess => 'Prístup pre hostí'; + + @override + String get repeater_guestAccessSubtitle => + 'Umožniť prístup hosta iba na čítanie.'; + + @override + String get repeater_privacyMode => 'Režim ochrany súkromia'; + + @override + String get repeater_privacyModeSubtitle => 'Skryť meno/poloha v reklamách'; + + @override + String get repeater_advertisementSettings => 'Nastavenia reklamy'; + + @override + String get repeater_localAdvertInterval => 'Lokálna reklamná časová obdoba'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes minút'; + } + + @override + String get repeater_floodAdvertInterval => + 'Interval reklamnej povodňovej reklamy'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours hodín'; + } + + @override + String get repeater_encryptedAdvertInterval => 'Šifrovaný reklamný interval'; + + @override + String get repeater_dangerZone => 'Nebezpečná zóna'; + + @override + String get repeater_rebootRepeater => 'Restart Repetér'; + + @override + String get repeater_rebootRepeaterSubtitle => 'Resetovať vysielací prístroj'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Ste si istý, že chcete tento opakovač restartovať?'; + + @override + String get repeater_regenerateIdentityKey => 'Generovať kľúč identity'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Generovať nový pár verejných/privátnych kľúčov'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'Toto vytvorí nový identitu pre opakovač. Pokračovať?'; + + @override + String get repeater_eraseFileSystem => 'Vymažať Systémový Reťazec'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Formátovať systém opakujúcich sa súborov'; + + @override + String get repeater_eraseFileSystemConfirm => + 'VAROVANIE: Toto zmaže všetky dáta na opakovači. To sa nedá zrušiť!'; + + @override + String get repeater_eraseSerialOnly => + 'Odstránenie je dostupné len cez sériové rozhranie.'; + + @override + String repeater_commandSent(String command) { + return 'Poforovaný príkaz: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Chyba pri odeslaní príkazu: $error'; + } + + @override + String get repeater_confirm => 'Potvrdiť'; + + @override + String get repeater_settingsSaved => 'Nastavenia boli uložené úspešne.'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Chyba pri ukladaní nastavení: $error'; + } + + @override + String get repeater_refreshBasicSettings => 'Obnoviť základné nastavenia'; + + @override + String get repeater_refreshRadioSettings => 'Obnoviť Nastavenia Rádií'; + + @override + String get repeater_refreshTxPower => 'Obnoviť TX napájanie'; + + @override + String get repeater_refreshLocationSettings => 'Obnoviť Nastavenia Miesta'; + + @override + String get repeater_refreshPacketForwarding => 'Obnoviť smerovanie paketov'; + + @override + String get repeater_refreshGuestAccess => 'Obnoviť prístup hosťa'; + + @override + String get repeater_refreshPrivacyMode => 'Obnoviť Ochranný režim'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Obnoviť nastavenia reklamy'; + + @override + String repeater_refreshed(String label) { + return '$label sa znova načítalo'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Chyba pri obnovení $label'; + } + + @override + String get repeater_cliTitle => 'Opakovacia CLI'; + + @override + String get repeater_debugNextCommand => 'Oprava Nasledujúceho Príkaz'; + + @override + String get repeater_commandHelp => 'Pomoc'; + + @override + String get repeater_clearHistory => 'Vymazať históriu'; + + @override + String get repeater_noCommandsSent => + 'Zatiaľ neboli odeslané žiadne príkazy.'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Zadajte príkaz nižšie alebo použite rýchle príkazy'; + + @override + String get repeater_enterCommandHint => 'Zadajte príkaz...'; + + @override + String get repeater_previousCommand => 'Predchádzajúci príkaz'; + + @override + String get repeater_nextCommand => 'Nasledujúci príkaz'; + + @override + String get repeater_enterCommandFirst => 'Zadajte najprv príkaz'; + + @override + String get repeater_cliCommandFrameTitle => 'Rámok Príkaz CLI'; + + @override + String repeater_cliCommandError(String error) { + return 'Chyba: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Zísť meno'; + + @override + String get repeater_cliQuickGetRadio => 'Zísť po rádiu'; + + @override + String get repeater_cliQuickGetTx => 'Zísť TX'; + + @override + String get repeater_cliQuickNeighbors => 'Súsezný'; + + @override + String get repeater_cliQuickVersion => 'Verzia'; + + @override + String get repeater_cliQuickAdvertise => 'Reklama'; + + @override + String get repeater_cliQuickClock => 'Hodiny'; + + @override + String get repeater_cliHelpAdvert => 'Odosiela reklamnú balíček.'; + + @override + String get repeater_cliHelpReboot => + 'Resetuje zariadenie. (pozor, môže dôjsť k \'Timeoutu\', čo je normálne)'; + + @override + String get repeater_cliHelpClock => + 'Zobrazuje aktuálny čas podľa hodiniek zariadenia.'; + + @override + String get repeater_cliHelpPassword => + 'Nastaví nový administrátorský prístupový údaj pre zariadenie.'; + + @override + String get repeater_cliHelpVersion => + 'Zobrazuje verziu zariadenia a dátum zostavenia firmvéru.'; + + @override + String get repeater_cliHelpClearStats => + 'Resetuje rôzne štatistické počítadlá na nulu.'; + + @override + String get repeater_cliHelpSetAf => 'Nastavuje časový faktor.'; + + @override + String get repeater_cliHelpSetTx => + 'Nastavenie vysielacej sily LoRa v dBm. (potrebuje sa reštart na aplikáciu)'; + + @override + String get repeater_cliHelpSetRepeat => + 'Umožňuje alebo vypína zopakovaný príspevok pre tento uzol.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Server miestnosti) Ak je \'zapnuté\', potom bude povolený prístup s prázdnym heslom, ale nebude možné posielať správu do miestnosti. (iba čítať).'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Nastavuje maximálny počet skokov pre vstupný povelový paket (ak je >= max, paket nie je preposlaný)'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Nastavuje hranicu ruživeho ladenia (v dB). Predvolené je 14. Nastavením na 0 sa vypne detekcia ruživeho ladenia kanálu.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Nastavuje interval na reštartovanie Auto Gain Controlleru. Nastavenie na 0 vypne funkciu.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Povolí alebo pozastaví funkciiu \"dvojité potvrdenia\".'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Nastavuje interval časovača v minútach na odošle miestny (bezprostredný) reklamný paket. Nastavenie na 0 vypne funkciu.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Nastavuje interval časovača v hodinách na odeslanie reklamnej vlne. Nastavenie na 0 vypne.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Nastavuje/aktualizuje heslo hosťa. (pre opakované pripojenia môžu hosťovské prihlásenia posielať požadanie \"Get Stats\")'; + + @override + String get repeater_cliHelpSetName => 'Nastaví názov reklamy.'; + + @override + String get repeater_cliHelpSetLat => + 'Nastaví geografickú šírku reklamnej mapy. (desatinné stupne)'; + + @override + String get repeater_cliHelpSetLon => + 'Nastavuje longitudinu reklamnej mapy. (desatinné stupne)'; + + @override + String get repeater_cliHelpSetRadio => + 'Nastavuje úplne nové parametre rádia a uloží ich do preferencií. Požaduje príkaz \"reboot\" na aplikáciu.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Nastavenia (experimentálne) základné (musi byť > 1 pre účel) na aplikáciu mierneho onesenia prijatých paketov, na základe signálu/skóre. Nastavenie na 0 vypne.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Nastavuje faktor násobený časom na vzduchu pre paket v režime povodňovej vlny a s náhodným systémom slotov, aby sa oneskorene jeho prenosovanie (s cieľom znížiť pravdepodobnosť kolízii).'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Podobne ako txdelay, ale pre aplikáciu náhodného oneskorenia pri preposlaní paketov v režime priameho prenosu.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => 'Aktivovať/Zatvárať most.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Nastaviť odklad pred retransmisiou paketov.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Zvolte, či bude most retransmitovať prijaté alebo vysielané balíčky.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Nastavte sériový link baudrate pre rs232 mosty.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Nastaviť tajomstvo mosta pre eshnow mosty.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Nastavuje vlastný faktor na úpravu nahlásenej batériovej napätia (podporované len na vybraných doskách).'; + + @override + String get repeater_cliHelpTempRadio => + 'Nastaví dočasné rádiové parametre pre zadaný počet minút, po skončení sa vráti k pôvodným rádiovým parametrom. (nepočuva sa do preferencií).'; + + @override + String get repeater_cliHelpSetPerm => + 'Zmení ACL. Odstráni zodpovedný záznam (podľa prefixa pubkey), ak je \"permissions\" rovné 0. Pridá nový záznam, ak je pubkey-hex plnej dĺžky a momentálne sa nenachádza v ACL. Aktualizuje záznam podľa zodpovedajúceho prefixa pubkey. Bitové oprávnenia sa líšia podľa funkčnej roly, ale nízke 2 bity sú: 0 (Hostiteľ), 1 (Čítanie len), 2 (Čítanie a zápis), 3 (Správca).'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Zísť typ mosta: žiadny, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => + 'Začína protokolovanie balíkov do systému súborov.'; + + @override + String get repeater_cliHelpLogStop => + 'Zastaví protokolovanie paketov do systémového súboru.'; + + @override + String get repeater_cliHelpLogErase => + 'Odstráni záznamy z balíkov z systému súborov.'; + + @override + String get repeater_cliHelpNeighbors => + 'Zobrazuje zoznam iných repeaterových uzlov zasielaných cez zero-hop reklamy. Každý riadok je id-prefix-hex:timestamp:snr-times-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Odstráni prvú zhodujúcu položku (podľa prefixu pubkey (hex)) z zoznamu susedov.'; + + @override + String get repeater_cliHelpRegion => + '(len sériál) Zobrazuje všetky definované regióny a aktuálne povolenia pre povodňové situácie.'; + + @override + String get repeater_cliHelpRegionLoad => + 'Poznámka: toto je špeciálna multi-príkázová inštancia. Každé nasledujúce príkaza je názov oblasti (zapustený s medzerami na indikáciu hierarchického pomeru, s minimálne jednou medzerou). Ukončené odeslaním prázdnej platnej linky/príkazu.'; + + @override + String get repeater_cliHelpRegionGet => + 'Hľadá región s daným príponou názvu (alebo \"\\\" pre globálny rozsah). Odpovedá \"-> región-název (rodič-název) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Pridá alebo aktualizuje definíciu regiónu s daným menom.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Odstráni definíciu oblasti s daným názvom. (musí zodpovedať presne a nemala by mať podoblasti)'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Nastavuje povolenie \'P\'lávu pre zadanú oblasť. (\'\' pre globálny/dedičský rozsah)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Odstráni povolenie \'F\'lood\' pre zadanú oblasť. (UPOZORNENIE: v tejto fáze nie je odporúčané ho používať na globálnom/dedskom rozsahu!!).'; + + @override + String get repeater_cliHelpRegionHome => + 'Odpovedá s aktuálnou \'domovskou\' oblasťou. (Poznámka aplikovaná zatiaľ nikde, vyhradené na budúce)'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Nastaví \'domovskú\' oblasť.'; + + @override + String get repeater_cliHelpRegionSave => + 'Uloží zoznam/mapu regiónov do úložiska.'; + + @override + String get repeater_cliHelpGps => + 'Zobrazuje stav GPS. Ak je GPS vypnutý, odpovedá len \"off\", ak je zapnutý, odpovedá s \"on\", stavom, fixom a počtom satelitov.'; + + @override + String get repeater_cliHelpGpsOnOff => 'Prepínač stavu GPS napájania.'; + + @override + String get repeater_cliHelpGpsSync => + 'Synchronizuje čas uzla s GPS hodinami.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Nastaví polohu uzla na GPS súradnice a uloží preferencie.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Poskytuje konfiguráciu reklamy pre uzol:\n- žiadna: nezahrňte polohu do reklám\n- zdieľať: zdieľajte GPS polohu (z SensorManager)\n- nastavenia: zobrazujte polohu uloženú v nastaveniach'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Nastavuje konfiguráciu reklamy na zadané miesto.'; + + @override + String get repeater_commandsListTitle => 'Zoznam príkazov'; + + @override + String get repeater_commandsListNote => + 'Poznámka: pre rôzne príkazy \"set ...\" existuje aj príkaz \"get ...\".'; + + @override + String get repeater_general => 'Obecné'; + + @override + String get repeater_settingsCategory => 'Nastavenia'; + + @override + String get repeater_bridge => 'Most'; + + @override + String get repeater_logging => 'Záznamy'; + + @override + String get repeater_neighborsRepeaterOnly => 'Súseznýci (iba opakovač)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Správa regiónov (iba opakovač)'; + + @override + String get repeater_regionNote => + 'Regionové príkazy boli zavádzané na správu regionálnych definícií a oprávnení.'; + + @override + String get repeater_gpsManagement => 'Správa GPS'; + + @override + String get repeater_gpsNote => + 'GPS príkaz bol zavádzaný na riadenie lokalitných tém.'; + + @override + String get telemetry_receivedData => 'Obdolené Telemetrické dáta'; + + @override + String get telemetry_requestTimeout => 'Požiadavka telemetrie zlyhala.'; + + @override + String telemetry_errorLoading(String error) { + return 'Chyba pri načítaní telemetrie: $error'; + } + + @override + String get telemetry_noData => 'Nejsú dostupné žiadne údaje z telemetrie.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Kanál $channel'; + } + + @override + String get telemetry_batteryLabel => 'Batéria'; + + @override + String get telemetry_voltageLabel => 'Napätie'; + + @override + String get telemetry_mcuTemperatureLabel => 'MCU teplota'; + + @override + String get telemetry_temperatureLabel => 'Teplota'; + + @override + String get telemetry_currentLabel => 'Aktuálne'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Cesta balíka'; + + @override + String get channelPath_viewMap => 'Zobraziť mapu'; + + @override + String get channelPath_otherObservedPaths => 'Ostatné pozorovacie cesty'; + + @override + String get channelPath_repeaterHops => 'Skoky opakovača'; + + @override + String get channelPath_noHopDetails => + 'Podrobnosti o balíčku zatiaľ nie sú dostupné.'; + + @override + String get channelPath_messageDetails => 'Podrobnosti o zprávach'; + + @override + String get channelPath_senderLabel => 'Posielateľ'; + + @override + String get channelPath_timeLabel => 'Čas'; + + @override + String get channelPath_repeatsLabel => 'Opakovanie'; + + @override + String channelPath_pathLabel(int index) { + return 'Cesta $index'; + } + + @override + String get channelPath_observedLabel => 'Pozorované'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Sledovaný postup $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'Žiadne údaje o polohe'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Neznáme'; + + @override + String get channelPath_floodPath => 'Povodňová'; + + @override + String get channelPath_directPath => 'Priamo'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 z $total skokov'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed z $total skokov'; + } + + @override + String get channelPath_mapTitle => 'Mapa Trasy'; + + @override + String get channelPath_noRepeaterLocations => + 'Pre túto cestu nie je dostupných žiadne polohy opakovačov.'; + + @override + String channelPath_primaryPath(int index) { + return 'Cesta $index (Hlavná)'; + } + + @override + String get channelPath_pathLabelTitle => 'Cesta'; + + @override + String get channelPath_observedPathHeader => 'Sledovaná cesta'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'Pre toto balíček nie sú dostupné údaje o skokoch.'; + + @override + String get channelPath_unknownRepeater => 'Neznáme opakovače'; + + @override + String get listFilter_tooltip => 'Filtrovať a triediť'; + + @override + String get listFilter_sortBy => 'Triediť podľa'; + + @override + String get listFilter_latestMessages => 'Posledné správy'; + + @override + String get listFilter_heardRecently => 'Nedávno počuli.'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Filtre'; + + @override + String get listFilter_all => 'Všetko'; + + @override + String get listFilter_users => 'Používatelia'; + + @override + String get listFilter_repeaters => 'Opakovadlá'; + + @override + String get listFilter_roomServers => 'Servéry miestnosti'; + + @override + String get listFilter_unreadOnly => 'Nezaregistrované len'; + + @override + String get listFilter_newGroup => 'Nová skupina'; +} diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart new file mode 100644 index 0000000..f95797b --- /dev/null +++ b/lib/l10n/app_localizations_sl.dart @@ -0,0 +1,2383 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Slovenian (`sl`). +class AppLocalizationsSl extends AppLocalizations { + AppLocalizationsSl([String locale = 'sl']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Kontakti'; + + @override + String get nav_channels => 'Kanali'; + + @override + String get nav_map => 'Karta'; + + @override + String get common_cancel => 'Prekliči'; + + @override + String get common_connect => 'Poveži se'; + + @override + String get common_unknownDevice => 'Nepoznano naprave'; + + @override + String get common_save => 'Shrani'; + + @override + String get common_delete => 'Izbrisati'; + + @override + String get common_close => 'Zapri'; + + @override + String get common_edit => 'Uredi'; + + @override + String get common_add => 'Dodaj'; + + @override + String get common_settings => 'Nastavitve'; + + @override + String get common_disconnect => 'Odklopiti'; + + @override + String get common_connected => 'Povezano'; + + @override + String get common_disconnected => 'Odprto'; + + @override + String get common_create => 'Ustvari'; + + @override + String get common_continue => 'Poudarki'; + + @override + String get common_share => 'Deliti'; + + @override + String get common_copy => 'Kopiraj'; + + @override + String get common_retry => 'Ponoviti'; + + @override + String get common_hide => 'Skrita'; + + @override + String get common_remove => 'Izbrisati'; + + @override + String get common_enable => 'Omogoči'; + + @override + String get common_disable => 'Izklopiti'; + + @override + String get common_reboot => 'Ponoviti'; + + @override + String get common_loading => 'Naložanje...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Skeniram za naprave...'; + + @override + String get scanner_connecting => 'Povezujem se...'; + + @override + String get scanner_disconnecting => 'Odklapljam se...'; + + @override + String get scanner_notConnected => 'Nezavezan'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Povezan s $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Iskanje naprav MeshCore...'; + + @override + String get scanner_tapToScan => + 'Nagneš na skeniranje za najdene naprave MeshCore.'; + + @override + String scanner_connectionFailed(String error) { + return 'Pošlo je z povezavo: $error'; + } + + @override + String get scanner_stop => 'Prekliči'; + + @override + String get scanner_scan => 'Skeniraj'; + + @override + String get device_quickSwitch => 'Hitro preklopiti'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Nastavitve'; + + @override + String get settings_deviceInfo => 'Informacije o napravei'; + + @override + String get settings_appSettings => 'Nastavitve aplikacije'; + + @override + String get settings_appSettingsSubtitle => + 'Obveščanja, sporoščanje in zemljevidi.'; + + @override + String get settings_nodeSettings => 'Nastavitve časa'; + + @override + String get settings_nodeName => 'Ime omrežno mesto'; + + @override + String get settings_nodeNameNotSet => 'Nezavedeno'; + + @override + String get settings_nodeNameHint => 'Vnesite ime časa'; + + @override + String get settings_nodeNameUpdated => 'Ime posodobljeno'; + + @override + String get settings_radioSettings => 'Nastavitve radija'; + + @override + String get settings_radioSettingsSubtitle => + 'Frekvenca, moč, razširni faktor'; + + @override + String get settings_radioSettingsUpdated => 'Radio nastavitve posodobljene'; + + @override + String get settings_location => 'Lokacija'; + + @override + String get settings_locationSubtitle => 'GPS koordinate'; + + @override + String get settings_locationUpdated => 'Lokacija posodobljena'; + + @override + String get settings_locationBothRequired => 'Vnesite širino in dolžino.'; + + @override + String get settings_locationInvalid => + 'Neveljna zemeljska širina ali dolžina.'; + + @override + String get settings_latitude => 'Širina'; + + @override + String get settings_longitude => 'Dolžina'; + + @override + String get settings_privacyMode => 'Mod podjetja'; + + @override + String get settings_privacyModeSubtitle => 'Skrita imena/lokacije v oglasih'; + + @override + String get settings_privacyModeToggle => + 'Omogoči način zasebnosti, da skrijemo tvoje ime in lokacijo v oglasih.'; + + @override + String get settings_privacyModeEnabled => 'Privatni režim je omogočen.'; + + @override + String get settings_privacyModeDisabled => 'Privatni režim je onemogočen.'; + + @override + String get settings_actions => 'Akcije'; + + @override + String get settings_sendAdvertisement => 'Pošlji Oglas'; + + @override + String get settings_sendAdvertisementSubtitle => + 'Trenutna prisotnost v oddajah'; + + @override + String get settings_advertisementSent => 'Oglas poslan'; + + @override + String get settings_syncTime => 'Ugasniti čas'; + + @override + String get settings_syncTimeSubtitle => 'Nastavi uro naprave v čas telefona'; + + @override + String get settings_timeSynchronized => 'Sinhronizirano po času'; + + @override + String get settings_refreshContacts => 'Ponovno obišči kontakte'; + + @override + String get settings_refreshContactsSubtitle => + 'Ponovno naloži seznam kontaktov iz naprave'; + + @override + String get settings_rebootDevice => 'Restart Naprave'; + + @override + String get settings_rebootDeviceSubtitle => + 'Ponovite zažetek naprave MeshCore'; + + @override + String get settings_rebootDeviceConfirm => + 'Ste prepričani, da želite ponovno zagon napravke? Boste odvisni od omrežja.'; + + @override + String get settings_debug => 'Napravi popravek'; + + @override + String get settings_bleDebugLog => 'Logarjev zapis BLE'; + + @override + String get settings_bleDebugLogSubtitle => + 'Navodila BLE, odgovori in surovo podatkovno'; + + @override + String get settings_appDebugLog => 'Log zapiske aplikacije'; + + @override + String get settings_appDebugLogSubtitle => 'Prijavni sporočila aplikacije'; + + @override + String get settings_about => 'Oglejte si'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => 'MeshCore Odprtokodni Projekt 2024'; + + @override + String get settings_aboutDescription => + 'Odprtokodni Flutter kličnik za naprave za LoRa mrežo MeshCore.'; + + @override + String get settings_infoName => 'Ime'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'Status'; + + @override + String get settings_infoBattery => 'Baterija'; + + @override + String get settings_infoPublicKey => 'Ključ javnega tipa'; + + @override + String get settings_infoContactsCount => 'Število kontaktov'; + + @override + String get settings_infoChannelCount => 'Število kanalov'; + + @override + String get settings_presets => 'Prednastavitve'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Frekvenca (MHz)'; + + @override + String get settings_frequencyHelper => '300,00 - 2500,00'; + + @override + String get settings_frequencyInvalid => 'Neveljčna frekvenca (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Pasovna širina'; + + @override + String get settings_spreadingFactor => 'Razširitveni faktor'; + + @override + String get settings_codingRate => 'Programska hitrost'; + + @override + String get settings_txPower => 'TX Moč (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Neveljaven TX moč (0-22 dBm)'; + + @override + String get settings_longRange => 'Dolenje območje'; + + @override + String get settings_fastSpeed => 'Hitra hitrost'; + + @override + String settings_error(String message) { + return 'Napaka: $message'; + } + + @override + String get appSettings_title => 'Nastavitve aplikacije'; + + @override + String get appSettings_appearance => 'Prikaži'; + + @override + String get appSettings_theme => 'Tema'; + + @override + String get appSettings_themeSystem => 'Predpomnilnik sistema'; + + @override + String get appSettings_themeLight => 'Luč'; + + @override + String get appSettings_themeDark => 'Temno'; + + @override + String get appSettings_language => 'Jezik'; + + @override + String get appSettings_languageSystem => 'Sistemska privzeta vrednost'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Obveščanja'; + + @override + String get appSettings_enableNotifications => 'Omogoči obveščanje'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Prejmujte obvestila o sporočilih in oglasih'; + + @override + String get appSettings_notificationPermissionDenied => + 'Odobritev obvestila zavrnjena'; + + @override + String get appSettings_notificationsEnabled => 'Obvestila omogočena'; + + @override + String get appSettings_notificationsDisabled => 'Obvestila so izklopljena'; + + @override + String get appSettings_messageNotifications => 'Obvestila'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Pokaži obvestilo ob prejemu novih sporočil.'; + + @override + String get appSettings_channelMessageNotifications => + 'Obvestila o sporočilih kanala'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Pokaži obvestilo ob prejemanju sporočil kanala'; + + @override + String get appSettings_advertisementNotifications => 'Opozorila o oglasih'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Pokaži obvestilo, ko so novi vozlišči odkrivljeni.'; + + @override + String get appSettings_messaging => 'Komuniciranje'; + + @override + String get appSettings_clearPathOnMaxRetry => + 'Ponovite pot do cilja na največjem štetju'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Ponovi pot zimske obveščevalne poti po 5 neuspešnih poskusih pošiljanja'; + + @override + String get appSettings_pathsWillBeCleared => + 'Potnice bodo očiščene po 5 neuspešnih poskusih.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Potniški poti ne bodo samodejno čiščeni.'; + + @override + String get appSettings_autoRouteRotation => 'Avtomatsko Občutke in Rotacije'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Med spreminjanjem med najboljšimi potmi in plovilnim načinom'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Samodejno krmilno rotiranje omogočeno'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Samodejno krmilno rotiranje je onemogočeno'; + + @override + String get appSettings_battery => 'Baterija'; + + @override + String get appSettings_batteryChemistry => 'Razem z možnostmi'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Nastavitve za naprave ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Povežite se z napravo za izbiro'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6–3,65 V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + + @override + String get appSettings_mapDisplay => 'Prikaz zemljevide'; + + @override + String get appSettings_showRepeaters => 'Prikaži ponovitve'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Prikaži ponovljalne notranjosti na zemljeploscu'; + + @override + String get appSettings_showChatNodes => 'Prikaži čakalne notranjosti'; + + @override + String get appSettings_showChatNodesSubtitle => + 'Prikaži pogovorni pike na zemljeploscu'; + + @override + String get appSettings_showOtherNodes => 'Pokaži druge vozlišča'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Pokaži druge vrste notranjih elementov na zemljevalu.'; + + @override + String get appSettings_timeFilter => 'Filtri po času'; + + @override + String get appSettings_timeFilterShowAll => 'Pokaži vse notranje elemente'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Pokaži notranjosti iz zadnjih $hours ur'; + } + + @override + String get appSettings_mapTimeFilter => 'Filtri časa zemljevida'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Pokaži notranje čepke, odkrivene v:'; + + @override + String get appSettings_allTime => 'Vse čase'; + + @override + String get appSettings_lastHour => 'Minuto nazaj'; + + @override + String get appSettings_last6Hours => 'Zadnjih 6 ur'; + + @override + String get appSettings_last24Hours => 'Zadnjih 24 ur'; + + @override + String get appSettings_lastWeek => 'Lepošno'; + + @override + String get appSettings_offlineMapCache => 'Omrezni Poudni Arhiv'; + + @override + String get appSettings_noAreaSelected => 'Nizkana označena površina'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Izbrano območje (povečava $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Napravi popravek'; + + @override + String get appSettings_appDebugLogging => 'Programski Log'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Log aplikacijske debug sporočila za odpravljanje težav'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'Omogočeno zaznamovanje napak v aplikaciji'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'Programski logi aplikacije so onemogočeni.'; + + @override + String get contacts_title => 'Kontakti'; + + @override + String get contacts_noContacts => 'Še ni kontaktov.'; + + @override + String get contacts_contactsWillAppear => + 'Kontakti se bodo prikazali, ko naprave oglasijo.'; + + @override + String get contacts_searchContacts => 'Iskanje kontaktov...'; + + @override + String get contacts_noUnreadContacts => 'Nerešeno kontaktov.'; + + @override + String get contacts_noContactsFound => + 'Niti ena osebe ali skupine ni najdena.'; + + @override + String get contacts_deleteContact => 'Izbrisati Kontakt'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Izbrisati $contactName iz kontaktov?'; + } + + @override + String get contacts_manageRepeater => 'Upravljajte Ponovitve'; + + @override + String get contacts_roomLogin => 'Vnos v sobo'; + + @override + String get contacts_openChat => 'Odprta kleta'; + + @override + String get contacts_editGroup => 'Uredi Skupino'; + + @override + String get contacts_deleteGroup => 'Izbrisati Skupino'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Odpovedati $groupName?'; + } + + @override + String get contacts_newGroup => 'Novo skupino'; + + @override + String get contacts_groupName => 'Skupina imena'; + + @override + String get contacts_groupNameRequired => 'Ime skupine je obvezno.'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'Skupina \"$name\" že obstaja'; + } + + @override + String get contacts_filterContacts => 'Filtri kontakt\\,...'; + + @override + String get contacts_noContactsMatchFilter => + 'Niti ena osebe ne ustreza vašemu kriteriju.'; + + @override + String get contacts_noMembers => 'Nič članov.'; + + @override + String get contacts_lastSeenNow => 'Datum zadnjega vpisa zdaj'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Zadnjič videti $minutes minut nazaj'; + } + + @override + String get contacts_lastSeenHourAgo => 'Zadnjič ogledan pred 1 uro.'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Zadnjič videti $hours ur nazaj'; + } + + @override + String get contacts_lastSeenDayAgo => 'Zadnjič ogledan pred 1 dnem'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Zadnjič videti $days dni nazaj'; + } + + @override + String get channels_title => 'Kanali'; + + @override + String get channels_noChannelsConfigured => 'Nekonfigurirane kanale'; + + @override + String get channels_addPublicChannel => 'Dodaj Objavni Kanal'; + + @override + String get channels_searchChannels => 'Poišči kanale...'; + + @override + String get channels_noChannelsFound => 'Niti kanalov najti ni.'; + + @override + String channels_channelIndex(int index) { + return 'Kanal $index'; + } + + @override + String get channels_hashtagChannel => 'Hashtag kanal'; + + @override + String get channels_public => 'javno'; + + @override + String get channels_private => 'Zasebno'; + + @override + String get channels_publicChannel => 'Ogljišna skupina'; + + @override + String get channels_privateChannel => 'Zatemniščen kanal'; + + @override + String get channels_editChannel => 'Uredi kanal'; + + @override + String get channels_deleteChannel => 'Pošlji kanal'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Izbrisati \"$name\"? To se ne da povrniti.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Kanal \"$name\" izbrisan.'; + } + + @override + String get channels_addChannel => 'Dodaj Kanal'; + + @override + String get channels_channelIndexLabel => 'Indeks kanala'; + + @override + String get channels_channelName => 'Ime kanala'; + + @override + String get channels_usePublicChannel => 'Uporabi javni kanal'; + + @override + String get channels_standardPublicPsk => 'Standardni javni PSK'; + + @override + String get channels_pskHex => 'PSK (Šestnajstbinska)'; + + @override + String get channels_generateRandomPsk => 'Generiraj naključni PSK'; + + @override + String get channels_enterChannelName => 'Vnesi ime kanala'; + + @override + String get channels_pskMustBe32Hex => + 'PSK mora biti 32 heksadecimalnih znakov.'; + + @override + String channels_channelAdded(String name) { + return 'Kanal \"$name\" dodan'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Uredi Kanal $index'; + } + + @override + String get channels_smazCompression => 'Kompresija SMAZ'; + + @override + String channels_channelUpdated(String name) { + return 'Kanal $name je bil posodobljen'; + } + + @override + String get channels_publicChannelAdded => 'javna skupnost dodana'; + + @override + String get channels_sortBy => 'Sortiraj po'; + + @override + String get channels_sortManual => 'Ročno'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => 'Najnovejše sporočilo'; + + @override + String get channels_sortUnread => 'Nerešeno'; + + @override + String get chat_noMessages => 'Še ni sporočil.'; + + @override + String get chat_sendMessageToStart => 'Pošlji sporočilo za začetek.'; + + @override + String get chat_originalMessageNotFound => + 'Opozorilo: Sporočilo ni bilo najdeno'; + + @override + String chat_replyingTo(String name) { + return 'Odgovarjanje $name'; + } + + @override + String chat_replyTo(String name) { + return 'Odpošlji odgovor $name'; + } + + @override + String get chat_location => 'Lokacija'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Pošlji sporočilo $contactName'; + } + + @override + String get chat_typeMessage => 'Vnesite sporočilo...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Pošiljanje sporočila je onemogočeno, saj je preveliko (maksimalno $maxBytes bajt).'; + } + + @override + String get chat_messageCopied => 'Pošljeno sporočilo'; + + @override + String get chat_messageDeleted => 'Pošiljanje sporočila izbrisano'; + + @override + String get chat_retryingMessage => 'Ponovna poskus.'; + + @override + String chat_retryCount(int current, int max) { + return 'Ponovit $current/$max'; + } + + @override + String get chat_sendGif => 'Pošlji GIF'; + + @override + String get chat_reply => 'Odpošlji'; + + @override + String get chat_addReaction => 'Dodaj Reakcijo'; + + @override + String get chat_me => 'jaz'; + + @override + String get emojiCategorySmileys => 'Emoji'; + + @override + String get emojiCategoryGestures => 'Gestikulacije'; + + @override + String get emojiCategoryHearts => 'Srce'; + + @override + String get emojiCategoryObjects => 'Predmeti'; + + @override + String get gifPicker_title => 'Izberi GIF'; + + @override + String get gifPicker_searchHint => 'Iskalite GIF-e...'; + + @override + String get gifPicker_poweredBy => 'Naprodno z GIPHY'; + + @override + String get gifPicker_noGifsFound => 'Niti GIF-jev najti ni.'; + + @override + String get gifPicker_failedLoad => 'Neuspešno je naložilo GIF-e'; + + @override + String get gifPicker_failedSearch => 'Posodobit neuspešno.'; + + @override + String get gifPicker_noInternet => 'Ni internetne povezave'; + + @override + String get debugLog_appTitle => 'Log zapiske aplikacije'; + + @override + String get debugLog_bleTitle => 'Logarjev zapis BLE'; + + @override + String get debugLog_copyLog => 'Kopiraj zapiske'; + + @override + String get debugLog_clearLog => 'Pasters log'; + + @override + String get debugLog_copied => 'Kopirana belež poteka.'; + + @override + String get debugLog_bleCopied => 'Kopirana beležke iz BLE'; + + @override + String get debugLog_noEntries => 'Še ni ustvarjenih debug zapisov.'; + + @override + String get debugLog_enableInSettings => + 'Omogoči beleženje napak v aplikaciji v nastavitvah'; + + @override + String get debugLog_frames => 'Okna'; + + @override + String get debugLog_rawLogRx => 'Svež Log-RX'; + + @override + String get debugLog_noBleActivity => 'Šele začnite z aktivnostjo BLE.'; + + @override + String debugFrame_length(int count) { + return 'Izhodni rob: $count bajtov'; + } + + @override + String debugFrame_command(String value) { + return 'Navodilo: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Obvestilo:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- Destinirano Ključno Besedilo: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Časovnik: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Ploki: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Tip besedila: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Preprosto'; + + @override + String debugFrame_text(String text) { + return '- Tekst: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Hex Dump:'; + + @override + String get chat_pathManagement => 'Upravljanje poti'; + + @override + String get chat_routingMode => 'Navodilo za usmerjevalni način'; + + @override + String get chat_autoUseSavedPath => 'Avto (uporabi shranjeno pot)'; + + @override + String get chat_forceFloodMode => 'Nasilje obvezati v način'; + + @override + String get chat_recentAckPaths => 'Nedavni poti ACK (tap za uporabo):'; + + @override + String get chat_pathHistoryFull => + 'Zapiske o poti so popolni. Izbriši vnose, da dodaš nove.'; + + @override + String get chat_hopSingular => 'skoč'; + + @override + String get chat_hopPlural => 'škrabec'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'Uspešni'; + + @override + String get chat_removePath => 'Izbriši pot'; + + @override + String get chat_noPathHistoryYet => + 'Še ni shranjenih poti.\nPošlji sporočilo za odkrivanje poti.'; + + @override + String get chat_pathActions => 'Potni ukazi:'; + + @override + String get chat_setCustomPath => 'Nastavi Prilozeno Pot'; + + @override + String get chat_setCustomPathSubtitle => 'Ročno določite potniško pot.'; + + @override + String get chat_clearPath => 'Čista pot'; + + @override + String get chat_clearPathSubtitle => 'Ob naslednji pošiljanju znova zbrati.'; + + @override + String get chat_pathCleared => + 'Pot je očiščena. Naslednje sporočilo bo ponovno odkril pot.'; + + @override + String get chat_floodModeSubtitle => + 'Uporabi tipko usmerjevanja v meniju aplikacije.'; + + @override + String get chat_floodModeEnabled => + 'Narejena je bila omrežna modaliteta. Vklopi jo znova preko ikone v meniju aplikacije.'; + + @override + String get chat_fullPath => 'Polni pot'; + + @override + String get chat_pathDetailsNotAvailable => + 'Podrobnosti poti zaenkrat niso na voljo. Poskusite poslati sporočilo za osvežitev.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Pot nastavljen: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Shrano lokalno. Povežite se za sinhronizacijo.'; + + @override + String get chat_pathDeviceConfirmed => 'Naprave potrjeno.'; + + @override + String get chat_pathDeviceNotConfirmed => 'Naprave še niso potrdile.'; + + @override + String get chat_type => 'Vnesite'; + + @override + String get chat_path => 'Pot'; + + @override + String get chat_publicKey => 'Ključ javnega tipa'; + + @override + String get chat_compressOutgoingMessages => 'Stisnite izhodne sporočila'; + + @override + String get chat_floodForced => 'Porolni (nasilje).'; + + @override + String get chat_directForced => 'Nezglašen (nasilje)'; + + @override + String chat_hopsForced(int count) { + return '$count skoki (nasilje)'; + } + + @override + String get chat_floodAuto => 'Preplavljenje (avtomatizirano)'; + + @override + String get chat_direct => 'Neposredni'; + + @override + String get chat_poiShared => 'Deljeno točke MN'; + + @override + String chat_unread(int count) { + return 'Nerešeno: $count'; + } + + @override + String get map_title => 'Mapa omrežja'; + + @override + String get map_noNodesWithLocation => + 'Nihče od notranjih elementov nima podatkov o lokaciji.'; + + @override + String get map_nodesNeedGps => + 'Omrežje morajo deliti svoje GPS koordinate,\nda se prikazajo na zemljeobrazniku.'; + + @override + String map_nodesCount(int count) { + return 'Omize: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Žigovi: $count'; + } + + @override + String get map_chat => 'Čistemar'; + + @override + String get map_repeater => 'Ponovitelj'; + + @override + String get map_room => 'Soba'; + + @override + String get map_sensor => 'Senzor'; + + @override + String get map_pinDm => 'Zavežite (DM)'; + + @override + String get map_pinPrivate => 'Zasebno označit'; + + @override + String get map_pinPublic => 'Oznaka (javna)'; + + @override + String get map_lastSeen => 'Zadnjič Zazet'; + + @override + String get map_disconnectConfirm => + 'Ste prepričani, da želite se odklopiti s tega naprave?'; + + @override + String get map_from => 'Od'; + + @override + String get map_source => 'Vir'; + + @override + String get map_flags => 'Zapestnice'; + + @override + String get map_shareMarkerHere => 'Delite točke tukaj.'; + + @override + String get map_pinLabel => 'Oznaka za pritrditev'; + + @override + String get map_label => 'Oznaka'; + + @override + String get map_pointOfInterest => 'Točka zanimivosti'; + + @override + String get map_sendToContact => 'Pošlji v kontakt'; + + @override + String get map_sendToChannel => 'Pošlji v kanal'; + + @override + String get map_noChannelsAvailable => 'Nihče kanalov na voljo.'; + + @override + String get map_publicLocationShare => 'Deljenje javne lokacije'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'Kljubite boste delili lokacijo v $channelLabel. Ta kanal je javno dostopen in vsak, ki ima PSK, ga lahko vidi.'; + } + + @override + String get map_connectToShareMarkers => + 'Povežite se z napravo za deljenje oznak.'; + + @override + String get map_filterNodes => 'Filtirirajte člene'; + + @override + String get map_nodeTypes => 'Vrste knope'; + + @override + String get map_chatNodes => 'Čuti zvezde'; + + @override + String get map_repeaters => 'Ponovljalniki'; + + @override + String get map_otherNodes => 'Druge vozlišča'; + + @override + String get map_keyPrefix => 'Predpona ključa'; + + @override + String get map_filterByKeyPrefix => 'Filtri po predpomniku ključa'; + + @override + String get map_publicKeyPrefix => 'Predifika javnega ključa'; + + @override + String get map_markers => 'Označitelji'; + + @override + String get map_showSharedMarkers => 'Pokaži skupno označenja'; + + @override + String get map_lastSeenTime => 'Datum zadnjega vpogleda'; + + @override + String get map_sharedPin => 'Deljeno naslovno geslo'; + + @override + String get map_joinRoom => 'Pridružiti sobo'; + + @override + String get map_manageRepeater => 'Upravljajte Ponovitve'; + + @override + String get mapCache_title => + 'Omrezni predpomnilnik zemljeških zemljejevskih slik'; + + @override + String get mapCache_selectAreaFirst => + 'Izberite območje za prvo predpomnilnik.'; + + @override + String get mapCache_noTilesToDownload => + 'Nihče slik ne bo naložil za to območje.'; + + @override + String get mapCache_downloadTilesTitle => 'Naloži ploščice'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Naložiť $count plošč za uporabo v režimu brez povezave?'; + } + + @override + String get mapCache_downloadAction => 'Naloži'; + + @override + String mapCache_cachedTiles(int count) { + return 'Pospešeno shranjeni $count plošč'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Shranjeni $downloaded ploščad ($failed neuspešno)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => + 'Ponovite arhiv za offline način'; + + @override + String get mapCache_clearOfflineCachePrompt => + 'Izbriši vse predpomnilnikovane kartografske ploščice?'; + + @override + String get mapCache_offlineCacheCleared => + 'Omrezni predpomnik je bil izbrisal.'; + + @override + String get mapCache_noAreaSelected => 'Nizona označena površina'; + + @override + String get mapCache_cacheArea => 'Omanski prostor'; + + @override + String get mapCache_useCurrentView => 'Uporabi trenutni prikaz'; + + @override + String get mapCache_zoomRange => 'Občutek razpona'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Predvideni ploščadi: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Naloženo $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Naloži ploščice'; + + @override + String get mapCache_clearCacheButton => 'Ponoviti arhiv'; + + @override + String mapCache_failedDownloads(int count) { + return 'Poslovniški izniki: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Takoj'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes minut nazaj'; + } + + @override + String time_hoursAgo(int hours) { + return '${hours}h nazaj'; + } + + @override + String time_daysAgo(int days) { + return '$days dni nazaj'; + } + + @override + String get time_hour => 'ure'; + + @override + String get time_hours => 'ure'; + + @override + String get time_day => 'dan'; + + @override + String get time_days => 'dani'; + + @override + String get time_week => 'teden'; + + @override + String get time_weeks => 'tedne'; + + @override + String get time_month => 'mesec'; + + @override + String get time_months => 'mesi'; + + @override + String get time_minutes => 'minute'; + + @override + String get time_allTime => 'Vse časovno obdobje'; + + @override + String get dialog_disconnect => 'Odklopiti'; + + @override + String get dialog_disconnectConfirm => + 'Ste prepričani, da želite se odklopiti s tega naprave?'; + + @override + String get login_repeaterLogin => 'Ponovni vnos'; + + @override + String get login_roomLogin => 'Vnos v sobo'; + + @override + String get login_password => 'Geslo'; + + @override + String get login_enterPassword => 'Vnesite geslo'; + + @override + String get login_savePassword => 'Shrani geslo'; + + @override + String get login_savePasswordSubtitle => + 'Geslo bo shranjeno varno na tem pripravem.'; + + @override + String get login_repeaterDescription => + 'Vnesite geslo za ponovljalnik, da dostopite do nastavitev in statusa.'; + + @override + String get login_roomDescription => + 'Vnesite geslo v sobo za dostop do nastavitev in statusa.'; + + @override + String get login_routing => 'Usmerjanje'; + + @override + String get login_routingMode => 'Navodilo za usmerjevalni način'; + + @override + String get login_autoUseSavedPath => 'Avto (uporabi shranjeno pot)'; + + @override + String get login_forceFloodMode => 'Nasilje obvezati v način'; + + @override + String get login_managePaths => 'Upravljajte Potniške Proti'; + + @override + String get login_login => 'Prijava'; + + @override + String login_attempt(int current, int max) { + return 'Poskušajo $current/$max'; + } + + @override + String login_failed(String error) { + return 'Prijava je bila neuspešna: $error'; + } + + @override + String get common_reload => 'Ponovno naloži'; + + @override + String get common_clear => 'Ponoviti'; + + @override + String path_currentPath(String path) { + return 'Trenutna pot: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Uporablja $count $_temp0 pot'; + } + + @override + String get path_enterCustomPath => 'Vnesite prilagojeno pot'; + + @override + String get path_currentPathLabel => 'Trenutna pot'; + + @override + String get path_hexPrefixInstructions => + 'Vnesite 2-karakterne heksadecimalne prefixe za vsako skopo, ločeno z zvezekami.'; + + @override + String get path_hexPrefixExample => + 'Primer: A1,F2,3C (vsak notranji element uporablja prvi bajt svojega javnega ključa)'; + + @override + String get path_labelHexPrefixes => 'Pot (heksafixne skrajšave)'; + + @override + String get path_helperMaxHops => + 'Maksimalno 64 skokov. Vsak prefiks je 2 heksadecimalna znamenja (1 bajt).'; + + @override + String get path_selectFromContacts => 'Izberi iz kontaktov:'; + + @override + String get path_noRepeatersFound => + 'Ne najdenih ponoviteljev ali strežnikov sob.'; + + @override + String get path_customPathsRequire => + 'Prilojene poti zahtevajo medhodne prenose, ki lahko prenašajo sporočila.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Neveljačni šesteročlenski prefiksi: $prefixes'; + } + + @override + String get path_tooLong => 'Pot je prevelika. Dovoljeno največ 64 skokov.'; + + @override + String get path_setPath => 'Nastavi Pot'; + + @override + String get repeater_management => 'Upravljanje ponovitve'; + + @override + String get repeater_managementTools => 'Upravne orodje'; + + @override + String get repeater_status => 'Status'; + + @override + String get repeater_statusSubtitle => + 'Pogledati stanje, statistike in sosede repeatera'; + + @override + String get repeater_telemetry => 'Telemetrija'; + + @override + String get repeater_telemetrySubtitle => + 'Pogledate telemetrijo senzorjev in sistemske statistike'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => + 'Pošlji ukazne povelje na ponovitveno enoto.'; + + @override + String get repeater_settings => 'Nastavitve'; + + @override + String get repeater_settingsSubtitle => + 'Konfigurirajte parametre ponovitelja'; + + @override + String get repeater_statusTitle => 'Status ponovitelja'; + + @override + String get repeater_routingMode => 'Navodilo za usmerjevalni način'; + + @override + String get repeater_autoUseSavedPath => 'Avto (uporabi shranjeno pot)'; + + @override + String get repeater_forceFloodMode => 'Nasilje obvezati v način'; + + @override + String get repeater_pathManagement => 'Upravljanje poti'; + + @override + String get repeater_refresh => 'Ponovno obnavljati'; + + @override + String get repeater_statusRequestTimeout => 'Zahtev statusa je iztekla.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Napaka pri obnašanju: $error'; + } + + @override + String get repeater_systemInformation => 'Informacije o sistemu'; + + @override + String get repeater_battery => 'Baterija'; + + @override + String get repeater_clockAtLogin => 'Ure (pri prijavi)'; + + @override + String get repeater_uptime => 'Čas delovanja'; + + @override + String get repeater_queueLength => 'Dolžina čakalne vrste'; + + @override + String get repeater_debugFlags => 'Nastavitve odpravilnosti'; + + @override + String get repeater_radioStatistics => 'Radio Statistika'; + + @override + String get repeater_lastRssi => 'Potredno RSSI'; + + @override + String get repeater_lastSnr => 'Nazadnje zabeležena SNR'; + + @override + String get repeater_noiseFloor => 'Šumovita raven'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Statistika paketa'; + + @override + String get repeater_sent => 'Pošljeno'; + + @override + String get repeater_received => 'Prejeto'; + + @override + String get repeater_duplicates => 'Duplikati'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days dni ${hours}h ${minutes}m ${seconds}s'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Skupno: $total, Poplava: $flood, Neposredno: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Skupno: $total, Poplava: $flood, Neposredno: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Prah: $flood, Neposredni: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Skupno: $total'; + } + + @override + String get repeater_settingsTitle => 'Nastavitve ponovitelja'; + + @override + String get repeater_basicSettings => 'Osnovne nastavitve'; + + @override + String get repeater_repeaterName => 'Ime ponovitelja'; + + @override + String get repeater_repeaterNameHelper => 'Prikaz imena za ta ponovitelj.'; + + @override + String get repeater_adminPassword => 'Admin geslo'; + + @override + String get repeater_adminPasswordHelper => 'Polni dostopno geslo'; + + @override + String get repeater_guestPassword => 'Geslo gostača'; + + @override + String get repeater_guestPasswordHelper => 'Odpovedni dostopni geslo'; + + @override + String get repeater_radioSettings => 'Nastavitve Radija'; + + @override + String get repeater_frequencyMhz => 'Frekvenca (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Moč'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Pasovna širina'; + + @override + String get repeater_spreadingFactor => 'Razširitveni faktor'; + + @override + String get repeater_codingRate => 'Programska hitrost'; + + @override + String get repeater_locationSettings => 'Nastavitve lokacije'; + + @override + String get repeater_latitude => 'Širina'; + + @override + String get repeater_latitudeHelper => 'Desetbinske protiure (npr. 37.7749)'; + + @override + String get repeater_longitude => 'Dolžina'; + + @override + String get repeater_longitudeHelper => + 'Desetbinske protiure (npr. -122,4194)'; + + @override + String get repeater_features => 'Značilnosti'; + + @override + String get repeater_packetForwarding => 'Usmerjanje paketa'; + + @override + String get repeater_packetForwardingSubtitle => + 'Omogoči ponovitelja za usmerjanje paketov.'; + + @override + String get repeater_guestAccess => 'Prijemnik'; + + @override + String get repeater_guestAccessSubtitle => + 'Omogoči dostop gostom v samo bralni načinu.'; + + @override + String get repeater_privacyMode => 'Privatni način'; + + @override + String get repeater_privacyModeSubtitle => 'Skrita imena/lokacije v oglasih'; + + @override + String get repeater_advertisementSettings => 'Nastavitve oglasnika'; + + @override + String get repeater_localAdvertInterval => 'Lokalen Oglasovni Razpon'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes minut'; + } + + @override + String get repeater_floodAdvertInterval => 'Razpon Obvestil o Poplavah'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours ur'; + } + + @override + String get repeater_encryptedAdvertInterval => + 'Šifrirana Oglasovalska Trajanje'; + + @override + String get repeater_dangerZone => 'Opozorilo'; + + @override + String get repeater_rebootRepeater => 'Ponovni zagon Repeaterja'; + + @override + String get repeater_rebootRepeaterSubtitle => 'Ponovni zagon ponovitelja.'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Ste prepričani, da želite ponovno zagon tega ponovitelja?'; + + @override + String get repeater_regenerateIdentityKey => 'Ponovite Ključ Identnosti'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Ustvarite novo par javnih/zasebnih ključev'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'To bo ustvaril novo identiteto za ponavljalnik. Prijavite se?'; + + @override + String get repeater_eraseFileSystem => 'Počisti Sustav Vajah'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Oblikuj datoteko ponovitve sistema'; + + @override + String get repeater_eraseFileSystemConfirm => + 'OPOZORILO: To bo izbrisal/a vsa dejstva na ponovilu. To ni mogoče povzvrniti!'; + + @override + String get repeater_eraseSerialOnly => + 'Brisanje je na voljo samo preko serijske konzole.'; + + @override + String repeater_commandSent(String command) { + return 'Navodilo poslano: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Napaka pri pošiljanju ukaznega: $error'; + } + + @override + String get repeater_confirm => 'Potrdit'; + + @override + String get repeater_settingsSaved => 'Nastavitve so shranjene uspešno.'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Napaka pri shranjevanju nastavitev: $error'; + } + + @override + String get repeater_refreshBasicSettings => + 'Ponovno nastavi osnovne nastavitve'; + + @override + String get repeater_refreshRadioSettings => 'Ponovno Nastavitve Radija'; + + @override + String get repeater_refreshTxPower => 'Ponovno nastavi TX moč'; + + @override + String get repeater_refreshLocationSettings => + 'Ponovno Nastavi Nastavitve Lokacije'; + + @override + String get repeater_refreshPacketForwarding => + 'Ponovno nastavitve usmerjevanja paketa'; + + @override + String get repeater_refreshGuestAccess => 'Ponovno nastavitve dostopa gostov'; + + @override + String get repeater_refreshPrivacyMode => + 'Ponovno aktiviraj način zasebnosti'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Ponovno nastavi Oglede Oglasi'; + + @override + String repeater_refreshed(String label) { + return '$label je bil/a posodobljen/a'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Napaka pri osveževanju $label'; + } + + @override + String get repeater_cliTitle => 'Ponovitelj CLI'; + + @override + String get repeater_debugNextCommand => 'Popravi naslednje ukazne možnosti'; + + @override + String get repeater_commandHelp => 'Pomoc'; + + @override + String get repeater_clearHistory => 'Ponovi zgodovino'; + + @override + String get repeater_noCommandsSent => + 'Niti ena ukazne povratne informacije še ni poslana.'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Vnesite ukaz spodaj ali uporabite hitre ukaze'; + + @override + String get repeater_enterCommandHint => 'Vnesite ukaz...'; + + @override + String get repeater_previousCommand => 'Prejšnji ukaz'; + + @override + String get repeater_nextCommand => 'Naslednja ukazna'; + + @override + String get repeater_enterCommandFirst => 'Vnesite ukaz najprej'; + + @override + String get repeater_cliCommandFrameTitle => 'Okno ukazne vrstice'; + + @override + String repeater_cliCommandError(String error) { + return 'Napaka: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Dobiti ime'; + + @override + String get repeater_cliQuickGetRadio => 'Dobiti Radiopravo'; + + @override + String get repeater_cliQuickGetTx => 'Dobiti TX'; + + @override + String get repeater_cliQuickNeighbors => 'Sosedi'; + + @override + String get repeater_cliQuickVersion => 'Različica'; + + @override + String get repeater_cliQuickAdvertise => 'Oglasite'; + + @override + String get repeater_cliQuickClock => 'Urnik'; + + @override + String get repeater_cliHelpAdvert => 'Pošlje paket oglasov'; + + @override + String get repeater_cliHelpReboot => + 'Ponastavi naprave. (Opomba, lahko pride do \'Timeouta\', kar je normalno)'; + + @override + String get repeater_cliHelpClock => 'Prikaže trenutno uro po uri naprave.'; + + @override + String get repeater_cliHelpPassword => + 'Nastavi novo administracijsko geslo za naprave.'; + + @override + String get repeater_cliHelpVersion => + 'Prikaže različico naprave in datum izrabe strojne opreme.'; + + @override + String get repeater_cliHelpClearStats => + 'Ponastavi različne statistične števke na nič.'; + + @override + String get repeater_cliHelpSetAf => 'Nastavi časovni koeficient.'; + + @override + String get repeater_cliHelpSetTx => + 'Nastavi moč LoRa oddajanja v dBm. (za ponovni zagon za uporabo)'; + + @override + String get repeater_cliHelpSetRepeat => + 'Omogoči ali onemogoči vlogo ponovitelja za tono.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Osebni strežnik) Če je \'vklopljeno\', potem bo dovoljeno prijavo z praznim geslom, vendar ne bo mogoče objaviti v sobo. (samo branje).'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Nastavi največjo število skokov za vstopne poplave (če je >= maks, paket ni usmerjen)'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Nastavi Prag Interferencij (v dB). Privzeto je 14. Nastavi na 0 za onemogočitev zaznavanja interferenc kanalov.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Nastavi časovno razdaljo za ponovni zagon nadzornika Avtomatske uteži. Nastavi na 0 za onemogočanje.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Omogoči ali onemogoči funkcijo \"dvojakih potrdil\".'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Nastavi časovno obmesto v minutah za pošiljanje lokalnega (brezposrednega) napovednega paketa. Nastavi na 0 za onemogočiti.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Nastavi časovno obmesto v urah za pošiljanje plovilnega oglasnega paketa. Nastavi na 0 za onemogočanje.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Nastavi/posodobi geslo gosta. (za ponovitve lahko gostov prijavi pošiljajo zahtevo \"Get Stats\")'; + + @override + String get repeater_cliHelpSetName => 'Nastavi ime oglasnika.'; + + @override + String get repeater_cliHelpSetLat => + 'Nastavi zemljepisno širino oglaševalskega zemljevida (desetdeljne).'; + + @override + String get repeater_cliHelpSetLon => + 'Nastavi zemljevidno širino oglasnika. (desetdelne stopnje)'; + + @override + String get repeater_cliHelpSetRadio => + 'Nastavi popolnoma nove radijske parametre in jih shranjuje v nastavitve. Za uporabo je potrebna \"restart\" ukaz.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Nastavitve (eksperimentalne) osnova (mora biti > 1 za učinkovanje) za uporabo rahle zakasnitve prejetih paketov, glede na moč signala/rezultat. Nastavite na 0 za onemogočanje.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Nastavi faktor, ki se množi s časom delovanja za paket v načinu poplavnega režima in z randomiziranim sistemom slotov, da odvrne njegovo posredovanje. (da se zmanjša verjetnost kolizij)'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Ima podobno vrednost kot txdelay, vendar jo lahko uporabite za dodajanje naknadnega zamika pri posredovanju paketov v režimu neposredne prevodi.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => 'Omogoči/Preklopi most.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Nastavi zamik pred ponovnim poslanjem paketov.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Izberite, ali bodo most ponavljali prejeto ali poslan paket.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Nastavi hitrost serijske povezave za mostove rs232.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Nastavi skrivni dostop za mostove ESPNOW.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Nastavi prilagoditev faktorja za prilagoditev poravnalnega napetosti baterije (podprt le na izbranih ploščah).'; + + @override + String get repeater_cliHelpTempRadio => + 'Nastavi začasne radio parametre za določeno časovno obdobje, kar po preteku časa vrne originalne radio parametre. (ne shranjuje v preferencije).'; + + @override + String get repeater_cliHelpSetPerm => + 'Modificira ACL. Odstrani ustreznu vnos (po predponi pubkeyja), če je \"permissions\" enako nič. Dodaja nov vnos, če je pubkey-hex v celoti in trenutno ni v ACL. Posodobi vnos po ustreznem predponi pubkeyja. Bitje dovoljenj se razlikuje glede na firmware vlogo, vendar so prvi dve bitki: 0 (Gost), 1 (Lezenje samo), 2 (Lezenje in pisanje), 3 (Administrator).'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Dobrodošli pri izbiri vrste mostu: brez, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => + 'Začnete beleženje paketov v datotekovni sistem.'; + + @override + String get repeater_cliHelpLogStop => + 'Ustavite beleženje paketov v datotečno sistem.'; + + @override + String get repeater_cliHelpLogErase => + 'Izbriše pakete zapisov iz datotek sistema.'; + + @override + String get repeater_cliHelpNeighbors => + 'Prikaže seznam drugih ponovnih knopov, do katerih je prišlo preko brezposrednih oglasov. Vsaka vrstica je id-prefix-hex:timestamp:snr-times-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Izbriše prvo ustreznu postavko (po predpomnilku pubkey (heks),) iz seznama sosedov.'; + + @override + String get repeater_cliHelpRegion => + '(Serija samo) Navaja vse definirane regije in trenutne poplave dovolilnosti.'; + + @override + String get repeater_cliHelpRegionLoad => + 'Opomba: to je posebna več ukazna pozivna operacija. Vsak naslednji ukaz je ime regije (z lezijami za prikaz hierarhije, z enim ustvarjenim razmislom). Zaključena s pošiljanjem praznega reda/ukaza.'; + + @override + String get repeater_cliHelpRegionGet => + 'Išče regijo s podanimi imenimi prefiksom (ali \"\\\" za globalni obseg). Odgovori se s \"-> regija-ime (rodič-ime) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Dodaja ali posodobi regijsko definicijo s podanim imenom.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Izbriše definicijo regije s podanim imenom. (mora se popolnoma ujemati in ne sme imeti podregij)'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Nastavi dovoljenje \'Nere\' za podano regijo. (\'\' za globalni/dedni obseg)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Odstrani dovoljenje \'F\'lood\' za podano regijo. (OPOZORILO: na tem koraku ni priporočljivo ga uporabljati na globalnem/dednem obsegu!!)'; + + @override + String get repeater_cliHelpRegionHome => + 'Odgovori z trenutnim \'domovim\' območjem. (Opomba je bila še nujno uporabljena, rezervirano za prihodnost)'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Nastavi regijo \'domov\'.'; + + @override + String get repeater_cliHelpRegionSave => + 'Shrani seznam/ zemljevzemi regij v shranjevanje.'; + + @override + String get repeater_cliHelpGps => + 'Pokaže status GPS-ja. Če je GPS izklopljen, odgovarja samo \"off\", če je vklopljen, odgovarja z \"on\", statusom, \"fix\" in štetjem satelitiv.'; + + @override + String get repeater_cliHelpGpsOnOff => 'Omogoči/onameni GPS način delovanja.'; + + @override + String get repeater_cliHelpGpsSync => + 'Sinhronizira čas časa ničala z gps uro.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Nastavi položaj časa na GPS koordinate in shranjevanje preferencij.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Omogoča konfiguracijo oglasi za notranjost člana:\n- none: ne vključevati lokacije v oglasih\n- share: deliti gps lokacijo (iz SensorManager)\n- prefs: oglaševati lokacijo shranjeno v preferencah'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Nastavi konfiguracijo oglasa na določenem mestu.'; + + @override + String get repeater_commandsListTitle => 'Seznam ukazov'; + + @override + String get repeater_commandsListNote => + 'Opomba: za različne ukaze \"nastavi ...\" obstaja tudi ukaz \"dobi ...\".'; + + @override + String get repeater_general => 'Općenito'; + + @override + String get repeater_settingsCategory => 'Nastavitve'; + + @override + String get repeater_bridge => 'Most'; + + @override + String get repeater_logging => 'Logiranje'; + + @override + String get repeater_neighborsRepeaterOnly => 'Sosedi (le za ponovitelja)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Upravljanje regij (zgolj za ponovitve)'; + + @override + String get repeater_regionNote => + 'Regionske ukazi so bili uvedeni za upravljanje z regijskimi definicijami in dovolili.'; + + @override + String get repeater_gpsManagement => 'Upravljanje GPS'; + + @override + String get repeater_gpsNote => + 'GPS ukaz je bil uveden za upravljanje z vprašanji, povezanimi z lokacijo.'; + + @override + String get telemetry_receivedData => 'Prejeto Telemetrično podatke'; + + @override + String get telemetry_requestTimeout => 'Zahtev telemetrije je iztekla.'; + + @override + String telemetry_errorLoading(String error) { + return 'Napaka pri obnašanju telemetrije: $error'; + } + + @override + String get telemetry_noData => 'Niso na voljo podatki o telemetriji.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Kanal $channel'; + } + + @override + String get telemetry_batteryLabel => 'Baterija'; + + @override + String get telemetry_voltageLabel => 'Napetost'; + + @override + String get telemetry_mcuTemperatureLabel => 'MCU Temperatura'; + + @override + String get telemetry_temperatureLabel => 'Temperatura'; + + @override + String get telemetry_currentLabel => 'Trenutno'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Pot do paketa'; + + @override + String get channelPath_viewMap => 'Prikaži zemljeznico'; + + @override + String get channelPath_otherObservedPaths => 'Drugi opazovani poti'; + + @override + String get channelPath_repeaterHops => 'Skoki ponovitelja'; + + @override + String get channelPath_noHopDetails => + 'Podrobnosti o paketu za dostavo niso navedene.'; + + @override + String get channelPath_messageDetails => 'Podrobnosti sporočila'; + + @override + String get channelPath_senderLabel => 'Pošiljalec'; + + @override + String get channelPath_timeLabel => 'Čas'; + + @override + String get channelPath_repeatsLabel => 'Ponovi'; + + @override + String channelPath_pathLabel(int index) { + return 'Pot $index'; + } + + @override + String get channelPath_observedLabel => 'Opazovani'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Opazovana pot $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'Nihče ni določil lokacije.'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Neznano'; + + @override + String get channelPath_floodPath => 'Prebivalstvo'; + + @override + String get channelPath_directPath => 'Neposredni'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 iz $total skokov'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed iz $total skokov'; + } + + @override + String get channelPath_mapTitle => 'Potni zemljevid'; + + @override + String get channelPath_noRepeaterLocations => + 'Ni na voljo nobenih lokacij za ponovitelja za to pot.'; + + @override + String channelPath_primaryPath(int index) { + return 'Pot $index (Glavni)'; + } + + @override + String get channelPath_pathLabelTitle => 'Pot'; + + @override + String get channelPath_observedPathHeader => 'Opazovana pot'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'Niso na voljo podrobnosti o letu.'; + + @override + String get channelPath_unknownRepeater => 'Nepoznati ponovitelj'; + + @override + String get listFilter_tooltip => 'Filtri in vrstiči'; + + @override + String get listFilter_sortBy => 'Sortiraj po'; + + @override + String get listFilter_latestMessages => 'Najnovejše sporočilo'; + + @override + String get listFilter_heardRecently => 'Nedavno slišan'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Filtri'; + + @override + String get listFilter_all => 'Vse'; + + @override + String get listFilter_users => 'Uporabniki'; + + @override + String get listFilter_repeaters => 'Ponovitve'; + + @override + String get listFilter_roomServers => 'Smeti za prostore'; + + @override + String get listFilter_unreadOnly => 'Nezbrani samo'; + + @override + String get listFilter_newGroup => 'Nova skupina'; +} diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart new file mode 100644 index 0000000..6f97659 --- /dev/null +++ b/lib/l10n/app_localizations_sv.dart @@ -0,0 +1,2366 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Swedish (`sv`). +class AppLocalizationsSv extends AppLocalizations { + AppLocalizationsSv([String locale = 'sv']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => 'Kontakter'; + + @override + String get nav_channels => 'Kanaler'; + + @override + String get nav_map => 'Karta'; + + @override + String get common_cancel => 'Avbryt'; + + @override + String get common_connect => 'Anslut'; + + @override + String get common_unknownDevice => 'Okänd enhet'; + + @override + String get common_save => 'Spara'; + + @override + String get common_delete => 'Radera'; + + @override + String get common_close => 'Stänga'; + + @override + String get common_edit => 'Redigera'; + + @override + String get common_add => 'Lägg till'; + + @override + String get common_settings => 'Inställningar'; + + @override + String get common_disconnect => 'Koppla från'; + + @override + String get common_connected => 'Ansluten'; + + @override + String get common_disconnected => 'Ansluten'; + + @override + String get common_create => 'Skapa'; + + @override + String get common_continue => 'Fortsätt'; + + @override + String get common_share => 'Dela'; + + @override + String get common_copy => 'Kopiera'; + + @override + String get common_retry => 'Försök igen'; + + @override + String get common_hide => 'Dölj'; + + @override + String get common_remove => 'Ta bort'; + + @override + String get common_enable => 'Aktivera'; + + @override + String get common_disable => 'Inaktivera'; + + @override + String get common_reboot => 'Start om'; + + @override + String get common_loading => 'Laddar...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => 'Söker efter enheter...'; + + @override + String get scanner_connecting => 'Anslutning...'; + + @override + String get scanner_disconnecting => 'Anslutning bryts...'; + + @override + String get scanner_notConnected => 'Inte ansluten'; + + @override + String scanner_connectedTo(String deviceName) { + return 'Ansluten till $deviceName'; + } + + @override + String get scanner_searchingDevices => 'Söker efter MeshCore-enheter...'; + + @override + String get scanner_tapToScan => 'Tryck Skanna för att hitta MeshCore-enheter'; + + @override + String scanner_connectionFailed(String error) { + return 'Anslutning misslyckades: $error'; + } + + @override + String get scanner_stop => 'Stoppa'; + + @override + String get scanner_scan => 'Skanna'; + + @override + String get device_quickSwitch => 'Snabb växling'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => 'Inställningar'; + + @override + String get settings_deviceInfo => 'Enhetens information'; + + @override + String get settings_appSettings => 'Appinställningar'; + + @override + String get settings_appSettingsSubtitle => + 'Meddelanden, notiser och kartinställningar'; + + @override + String get settings_nodeSettings => 'Nodinställningar'; + + @override + String get settings_nodeName => 'Nodnamn'; + + @override + String get settings_nodeNameNotSet => 'Inte angivet'; + + @override + String get settings_nodeNameHint => 'Ange nodnamn'; + + @override + String get settings_nodeNameUpdated => 'Namn uppdaterat'; + + @override + String get settings_radioSettings => 'Radioinställningar'; + + @override + String get settings_radioSettingsSubtitle => + 'Frekvens, effekt, spridningsfaktor'; + + @override + String get settings_radioSettingsUpdated => + 'Radioinställningarna har uppdaterats'; + + @override + String get settings_location => 'Plats'; + + @override + String get settings_locationSubtitle => 'GPS koordinater'; + + @override + String get settings_locationUpdated => 'Plats uppdaterad'; + + @override + String get settings_locationBothRequired => 'Ange både latitud och longitud.'; + + @override + String get settings_locationInvalid => 'Ogiltig latitud eller longitud.'; + + @override + String get settings_latitude => 'Latitud'; + + @override + String get settings_longitude => 'Längdgrad'; + + @override + String get settings_privacyMode => 'Privatläge'; + + @override + String get settings_privacyModeSubtitle => 'Dölj namn/plats i annonser'; + + @override + String get settings_privacyModeToggle => + 'Aktivera privatläge för att dölja ditt namn och din plats i annonser.'; + + @override + String get settings_privacyModeEnabled => 'Privatläget är aktiverat'; + + @override + String get settings_privacyModeDisabled => 'Privatläge är avstängt'; + + @override + String get settings_actions => 'Åtgärder'; + + @override + String get settings_sendAdvertisement => 'Skicka Annons'; + + @override + String get settings_sendAdvertisementSubtitle => 'Sändning finns nu'; + + @override + String get settings_advertisementSent => 'Annons skickad'; + + @override + String get settings_syncTime => 'Synkroniseringstid'; + + @override + String get settings_syncTimeSubtitle => 'Ställ enheten till telefonens tid'; + + @override + String get settings_timeSynchronized => 'Tidssynkroniserat'; + + @override + String get settings_refreshContacts => 'Uppdatera Kontakter'; + + @override + String get settings_refreshContactsSubtitle => + 'Ladda om kontaktlistan från enheten'; + + @override + String get settings_rebootDevice => 'Starta om enheten'; + + @override + String get settings_rebootDeviceSubtitle => 'Starta MeshCore-enheten'; + + @override + String get settings_rebootDeviceConfirm => + 'Är du säker på att du vill starta om enheten? Du kommer att bli avkopplad.'; + + @override + String get settings_debug => 'Felsök'; + + @override + String get settings_bleDebugLog => 'BLE-felsökning'; + + @override + String get settings_bleDebugLogSubtitle => 'BLE-kommandon, svar och rådata'; + + @override + String get settings_appDebugLog => 'Appfelsökning'; + + @override + String get settings_appDebugLogSubtitle => + 'Applikations felsökningsmeddelanden'; + + @override + String get settings_about => 'Om'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => '2024 MeshCore Öppen Källkodsprojekt'; + + @override + String get settings_aboutDescription => + 'En öppen källkods Flutter-klient för MeshCore LoRa meshnätverksenheter.'; + + @override + String get settings_infoName => 'Namn'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => 'Status'; + + @override + String get settings_infoBattery => 'Batteri'; + + @override + String get settings_infoPublicKey => 'Allmänt nyckel'; + + @override + String get settings_infoContactsCount => 'Kontakterantal'; + + @override + String get settings_infoChannelCount => 'Kanalantal'; + + @override + String get settings_presets => 'Fördefinierade inställningar'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => 'Frekvens (MHz)'; + + @override + String get settings_frequencyHelper => '300,0 - 2500,0'; + + @override + String get settings_frequencyInvalid => 'Ogiltig frekvens (300-2500 MHz)'; + + @override + String get settings_bandwidth => 'Bandbredd'; + + @override + String get settings_spreadingFactor => 'Spreadingfaktor'; + + @override + String get settings_codingRate => 'Kodningsgrad'; + + @override + String get settings_txPower => 'TX-effekt (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => 'Ogiltig TX-effekt (0-22 dBm)'; + + @override + String get settings_longRange => 'Lång räckvidd'; + + @override + String get settings_fastSpeed => 'Snabb hastighet'; + + @override + String settings_error(String message) { + return 'Fel: $message'; + } + + @override + String get appSettings_title => 'Appinställningar'; + + @override + String get appSettings_appearance => 'Utseende'; + + @override + String get appSettings_theme => 'Tema'; + + @override + String get appSettings_themeSystem => 'Systemstandard'; + + @override + String get appSettings_themeLight => 'Ljus'; + + @override + String get appSettings_themeDark => 'Mörk'; + + @override + String get appSettings_language => 'Språk'; + + @override + String get appSettings_languageSystem => 'Systemstandard'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => 'Meddelanden'; + + @override + String get appSettings_enableNotifications => 'Aktivera Notifikationer'; + + @override + String get appSettings_enableNotificationsSubtitle => + 'Ta emot notiser för meddelanden och reklam'; + + @override + String get appSettings_notificationPermissionDenied => + 'Tillåtelse för notifikationer nekad'; + + @override + String get appSettings_notificationsEnabled => 'Notifikationer aktiverade'; + + @override + String get appSettings_notificationsDisabled => 'Meddelanden är avstängda'; + + @override + String get appSettings_messageNotifications => 'Meddelandekrav'; + + @override + String get appSettings_messageNotificationsSubtitle => + 'Visa notis när nya meddelanden tas emot'; + + @override + String get appSettings_channelMessageNotifications => 'Kanalmeddelandena'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => + 'Visa notis när meddelanden i kanal mottas'; + + @override + String get appSettings_advertisementNotifications => 'Annonsmeddelanden'; + + @override + String get appSettings_advertisementNotificationsSubtitle => + 'Visa notis när nya noder upptäcks'; + + @override + String get appSettings_messaging => 'Meddelanden'; + + @override + String get appSettings_clearPathOnMaxRetry => 'Rensa Vägen på Max Försök'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => + 'Återställ kontaktväg efter 5 misslyckade försök att skicka'; + + @override + String get appSettings_pathsWillBeCleared => + 'Sökvägar kommer att tömmas efter 5 misslyckade försök.'; + + @override + String get appSettings_pathsWillNotBeCleared => + 'Sökvägar kommer inte att rensas automatiskt.'; + + @override + String get appSettings_autoRouteRotation => 'Automatisk Rutväxling'; + + @override + String get appSettings_autoRouteRotationSubtitle => + 'Blixtra mellan bästa vägar och flödesläge'; + + @override + String get appSettings_autoRouteRotationEnabled => + 'Automatisk ruttrotation är aktiverad'; + + @override + String get appSettings_autoRouteRotationDisabled => + 'Automatisk ruttrotation är avstängd'; + + @override + String get appSettings_battery => 'Batteri'; + + @override + String get appSettings_batteryChemistry => 'Batterikemi'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return 'Ställ in per enhet ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => + 'Anslut till en enhet för att välja'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3.0-4.2V)'; + + @override + String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6–3,65V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3.0-4.2V)'; + + @override + String get appSettings_mapDisplay => 'Kartvisning'; + + @override + String get appSettings_showRepeaters => 'Visa återuppslag'; + + @override + String get appSettings_showRepeatersSubtitle => + 'Visa återspelsnoder på kartan'; + + @override + String get appSettings_showChatNodes => 'Visa Chattnoder'; + + @override + String get appSettings_showChatNodesSubtitle => 'Visa chattnoder på kartan'; + + @override + String get appSettings_showOtherNodes => 'Visa andra noder'; + + @override + String get appSettings_showOtherNodesSubtitle => + 'Visa andra nodtyper på kartan'; + + @override + String get appSettings_timeFilter => 'Tidsfilter'; + + @override + String get appSettings_timeFilterShowAll => 'Visa alla noder'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return 'Visa noder från de senaste $hours timmarna'; + } + + @override + String get appSettings_mapTimeFilter => 'Karttid Filter'; + + @override + String get appSettings_showNodesDiscoveredWithin => + 'Visa noder som upptäckts inom:'; + + @override + String get appSettings_allTime => 'Totalen'; + + @override + String get appSettings_lastHour => 'Sista timmen'; + + @override + String get appSettings_last6Hours => 'De senaste 6 timmarna'; + + @override + String get appSettings_last24Hours => 'De senaste 24 timmarna'; + + @override + String get appSettings_lastWeek => 'Förra veckan'; + + @override + String get appSettings_offlineMapCache => 'Offline Kartcache'; + + @override + String get appSettings_noAreaSelected => 'Ingen area markerad'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return 'Område markerat (zoom $minZoom-$maxZoom)'; + } + + @override + String get appSettings_debugCard => 'Felsök'; + + @override + String get appSettings_appDebugLogging => 'App-felsökning och loggning'; + + @override + String get appSettings_appDebugLoggingSubtitle => + 'Logga appens felsökningsmeddelanden för felsökning'; + + @override + String get appSettings_appDebugLoggingEnabled => + 'App felsökning loggning aktiverad'; + + @override + String get appSettings_appDebugLoggingDisabled => + 'App felsökning är avstängd'; + + @override + String get contacts_title => 'Kontakter'; + + @override + String get contacts_noContacts => 'Inga kontakter ännu'; + + @override + String get contacts_contactsWillAppear => + 'Kontakter kommer att visas när enheter annonserar.'; + + @override + String get contacts_searchContacts => 'Sök kontakter...'; + + @override + String get contacts_noUnreadContacts => 'Inga oinlästa kontakter'; + + @override + String get contacts_noContactsFound => + 'Inga kontakter eller grupper hittades.'; + + @override + String get contacts_deleteContact => 'Ta bort Kontakt'; + + @override + String contacts_removeConfirm(String contactName) { + return 'Ta bort $contactName från kontakter?'; + } + + @override + String get contacts_manageRepeater => 'Hantera Upprepare'; + + @override + String get contacts_roomLogin => 'Rum Inloggning'; + + @override + String get contacts_openChat => 'Öppna Chatt'; + + @override + String get contacts_editGroup => 'Redigera Grupp'; + + @override + String get contacts_deleteGroup => 'Ta bort Grupp'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return 'Ta bort $groupName?'; + } + + @override + String get contacts_newGroup => 'Ny grupp'; + + @override + String get contacts_groupName => 'Gruppnamn'; + + @override + String get contacts_groupNameRequired => 'Gruppnamnet är obligatoriskt'; + + @override + String contacts_groupAlreadyExists(String name) { + return 'Gruppen \"$name\" finns redan.'; + } + + @override + String get contacts_filterContacts => 'Filtrera kontakter...'; + + @override + String get contacts_noContactsMatchFilter => + 'Inga kontakter matchar ditt filter'; + + @override + String get contacts_noMembers => 'Inga medlemmar'; + + @override + String get contacts_lastSeenNow => 'Senast synlig nu'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return 'Senast sedd $minutes min sedan'; + } + + @override + String get contacts_lastSeenHourAgo => 'Senast sedd för 1 timme sedan'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return 'Senast sedd $hours timmar sedan'; + } + + @override + String get contacts_lastSeenDayAgo => 'Senast sedd för 1 dag sedan'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return 'Senast synlig $days dagar sedan'; + } + + @override + String get channels_title => 'Kanaler'; + + @override + String get channels_noChannelsConfigured => 'Inga kanaler konfigurerade'; + + @override + String get channels_addPublicChannel => 'Lägg till publik kanal'; + + @override + String get channels_searchChannels => 'Sök kanaler...'; + + @override + String get channels_noChannelsFound => 'Inga kanaler hittades'; + + @override + String channels_channelIndex(int index) { + return 'Kanal $index'; + } + + @override + String get channels_hashtagChannel => 'Hashtagkanal'; + + @override + String get channels_public => 'Offentligt'; + + @override + String get channels_private => 'Privat'; + + @override + String get channels_publicChannel => 'Allmänt kanal'; + + @override + String get channels_privateChannel => 'Privat kanal'; + + @override + String get channels_editChannel => 'Redigera kanal'; + + @override + String get channels_deleteChannel => 'Ta bort kanal'; + + @override + String channels_deleteChannelConfirm(String name) { + return 'Radera \"$name\"? Detta kan inte ångras.'; + } + + @override + String channels_channelDeleted(String name) { + return 'Kanalen \"$name\" raderad'; + } + + @override + String get channels_addChannel => 'Lägg till kanal'; + + @override + String get channels_channelIndexLabel => 'Kanalindex'; + + @override + String get channels_channelName => 'Kanalnamn'; + + @override + String get channels_usePublicChannel => 'Använd Publikkanal'; + + @override + String get channels_standardPublicPsk => 'Standard allmän PSK'; + + @override + String get channels_pskHex => 'PSK (Hex)'; + + @override + String get channels_generateRandomPsk => 'Generera slumpmässig PSK'; + + @override + String get channels_enterChannelName => 'Ange en kanalnamn'; + + @override + String get channels_pskMustBe32Hex => 'PSK måste vara 32 hexadecimala tecken'; + + @override + String channels_channelAdded(String name) { + return 'Kanalen \"$name\" har lagts till'; + } + + @override + String channels_editChannelTitle(int index) { + return 'Redigera Kanal $index'; + } + + @override + String get channels_smazCompression => 'SMAZ-komprimering'; + + @override + String channels_channelUpdated(String name) { + return 'Kanalen \"$name\" har uppdaterats'; + } + + @override + String get channels_publicChannelAdded => 'Allmänt kanal tillagd'; + + @override + String get channels_sortBy => 'Sortera efter'; + + @override + String get channels_sortManual => 'Manuell'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => 'Senaste meddelanden'; + + @override + String get channels_sortUnread => 'Oläst'; + + @override + String get chat_noMessages => 'Inga meddelanden ännu'; + + @override + String get chat_sendMessageToStart => + 'Skicka ett meddelande för att komma igång'; + + @override + String get chat_originalMessageNotFound => + 'Originalt meddelande hittades inte'; + + @override + String chat_replyingTo(String name) { + return 'Svara till $name'; + } + + @override + String chat_replyTo(String name) { + return 'Svara till $name'; + } + + @override + String get chat_location => 'Plats'; + + @override + String chat_sendMessageTo(String contactName) { + return 'Skicka ett meddelande till $contactName'; + } + + @override + String get chat_typeMessage => 'Skriv ett meddelande...'; + + @override + String chat_messageTooLong(int maxBytes) { + return 'Meddelandet är för långt (max $maxBytes byte).'; + } + + @override + String get chat_messageCopied => 'Meddelandet kopierades'; + + @override + String get chat_messageDeleted => 'Meddelandet raderat'; + + @override + String get chat_retryingMessage => 'Försöker igen'; + + @override + String chat_retryCount(int current, int max) { + return 'Försök igen $current/$max'; + } + + @override + String get chat_sendGif => 'Skicka GIF'; + + @override + String get chat_reply => 'Svara'; + + @override + String get chat_addReaction => 'Lägg till reaktion'; + + @override + String get chat_me => 'Mig'; + + @override + String get emojiCategorySmileys => 'Emojis'; + + @override + String get emojiCategoryGestures => 'Gestikuleringar'; + + @override + String get emojiCategoryHearts => 'Hjärtan'; + + @override + String get emojiCategoryObjects => 'Objekt'; + + @override + String get gifPicker_title => 'Välj en GIF'; + + @override + String get gifPicker_searchHint => 'Sök GIF:ar...'; + + @override + String get gifPicker_poweredBy => 'Drivet av GIPHY'; + + @override + String get gifPicker_noGifsFound => 'Inga GIF-filer hittades'; + + @override + String get gifPicker_failedLoad => 'Kunde inte ladda GIF-filer'; + + @override + String get gifPicker_failedSearch => 'Sökningen misslyckades.'; + + @override + String get gifPicker_noInternet => 'Ingen internetanslutning'; + + @override + String get debugLog_appTitle => 'Appfelsökning'; + + @override + String get debugLog_bleTitle => 'BLE-felsökning'; + + @override + String get debugLog_copyLog => 'Kopiera logg'; + + @override + String get debugLog_clearLog => 'Rensa logg'; + + @override + String get debugLog_copied => 'Felsökningslogg kopierad'; + + @override + String get debugLog_bleCopied => 'BLE-logg kopierad'; + + @override + String get debugLog_noEntries => 'Inga felsökningsloggar ännu'; + + @override + String get debugLog_enableInSettings => + 'Aktivera appens felsökningsloggning i inställningarna'; + + @override + String get debugLog_frames => 'Rammar'; + + @override + String get debugLog_rawLogRx => 'Rå Log-RX'; + + @override + String get debugLog_noBleActivity => 'Ingen BLE-aktivitet ännu'; + + @override + String debugFrame_length(int count) { + return 'Ramstorlek: $count byte'; + } + + @override + String debugFrame_command(String value) { + return 'Kommando: 0x$value'; + } + + @override + String get debugFrame_textMessageHeader => 'Textmeddelandefält:'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '– Destination PubKey: $pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- Tidsstämpel: $timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- Flaggor: 0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- Texttyp: $type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => 'Enkel'; + + @override + String debugFrame_text(String text) { + return '- Text: \"$text\"'; + } + + @override + String get debugFrame_hexDump => 'Hexdump:'; + + @override + String get chat_pathManagement => 'Stigarhantering'; + + @override + String get chat_routingMode => 'Ruttläge'; + + @override + String get chat_autoUseSavedPath => 'Automatisk (använd sparad sökväg)'; + + @override + String get chat_forceFloodMode => 'Tvinga Översvämningsläge'; + + @override + String get chat_recentAckPaths => + 'Nyligen Ack-vägar (tryck för att använda):'; + + @override + String get chat_pathHistoryFull => + 'Historisk sökväg är full. Ta bort poster för att lägga till nya.'; + + @override + String get chat_hopSingular => 'hoppa'; + + @override + String get chat_hopPlural => 'hoppar'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => 'framgångar'; + + @override + String get chat_removePath => 'Ta bort sökväg'; + + @override + String get chat_noPathHistoryYet => + 'Ingen historik ännu.\nSkicka ett meddelande för att upptäcka spår.'; + + @override + String get chat_pathActions => 'Stigar:'; + + @override + String get chat_setCustomPath => 'Ange anpassad sökväg'; + + @override + String get chat_setCustomPathSubtitle => 'Ange ruttväg manuellt'; + + @override + String get chat_clearPath => 'Rensa Vägen'; + + @override + String get chat_clearPathSubtitle => 'Tvinga fram omstart vid nästa sändning'; + + @override + String get chat_pathCleared => + 'Routen är nu fri. Nästa meddelande kommer att upptäcka rutten igen.'; + + @override + String get chat_floodModeSubtitle => 'Använd routningsomkopplaren i appraden'; + + @override + String get chat_floodModeEnabled => + 'Översvämningsläge aktiverat. Stäng av via ruttikonen i appraden.'; + + @override + String get chat_fullPath => 'Fullständig sökväg'; + + @override + String get chat_pathDetailsNotAvailable => + 'Stigaruppgifterna är ännu inte tillgängliga. Försök att skicka ett meddelande för att uppdatera.'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hoppar', + one: 'hopp', + ); + return 'Sökväg inställd: $hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => + 'Sparat lokalt. Anslut för att synkronisera.'; + + @override + String get chat_pathDeviceConfirmed => 'Enheten bekräftad.'; + + @override + String get chat_pathDeviceNotConfirmed => 'Enheten har inte bekräftats ännu.'; + + @override + String get chat_type => 'Skriv'; + + @override + String get chat_path => 'Sökväg'; + + @override + String get chat_publicKey => 'Allmänt nyckel'; + + @override + String get chat_compressOutgoingMessages => 'Kryptera utgående meddelanden'; + + @override + String get chat_floodForced => 'Översvämning (tvingad)'; + + @override + String get chat_directForced => 'Direkt (tvingad)'; + + @override + String chat_hopsForced(int count) { + return '$count hopp (tvingat)'; + } + + @override + String get chat_floodAuto => 'Översvämning (auto)'; + + @override + String get chat_direct => 'Direkt'; + + @override + String get chat_poiShared => 'Delad POI'; + + @override + String chat_unread(int count) { + return 'Olästa: $count'; + } + + @override + String get map_title => 'Nodkarta'; + + @override + String get map_noNodesWithLocation => 'Inga noder med platsinformation'; + + @override + String get map_nodesNeedGps => + 'Noder måste dela sina GPS-koordinater\nför att visas på kartan'; + + @override + String map_nodesCount(int count) { + return 'Noder: $count'; + } + + @override + String map_pinsCount(int count) { + return 'Pinnar: $count'; + } + + @override + String get map_chat => 'Chat'; + + @override + String get map_repeater => 'Återuppspelare'; + + @override + String get map_room => 'Rum'; + + @override + String get map_sensor => 'Sensor'; + + @override + String get map_pinDm => 'Lås (DM)'; + + @override + String get map_pinPrivate => 'Lås (Privat)'; + + @override + String get map_pinPublic => 'Anslå (Offentligt)'; + + @override + String get map_lastSeen => 'Senast sedd'; + + @override + String get map_disconnectConfirm => + 'Är du säker på att du vill koppla från enheten?'; + + @override + String get map_from => 'Från'; + + @override + String get map_source => 'Källa'; + + @override + String get map_flags => 'Flaggor'; + + @override + String get map_shareMarkerHere => 'Dela markeringen här'; + + @override + String get map_pinLabel => 'Fästetikett'; + + @override + String get map_label => 'Etikett'; + + @override + String get map_pointOfInterest => 'Plats av intresse'; + + @override + String get map_sendToContact => 'Skicka till kontakt'; + + @override + String get map_sendToChannel => 'Skicka till kanal'; + + @override + String get map_noChannelsAvailable => 'Inga kanaler tillgängliga'; + + @override + String get map_publicLocationShare => 'Dela offentlig plats'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return 'Du håller på att dela en plats i $channelLabel. Denna kanal är offentlig och alla med PSK kan se den.'; + } + + @override + String get map_connectToShareMarkers => + 'Anslut till en enhet för att dela markörer'; + + @override + String get map_filterNodes => 'Filtrera noder'; + + @override + String get map_nodeTypes => 'Nodtyper'; + + @override + String get map_chatNodes => 'Chatnoder'; + + @override + String get map_repeaters => 'Upprepare'; + + @override + String get map_otherNodes => 'Andra noder'; + + @override + String get map_keyPrefix => 'Nyckelprefix'; + + @override + String get map_filterByKeyPrefix => 'Filtrera efter nyckelprefix'; + + @override + String get map_publicKeyPrefix => 'Allmänt nyckelprästegenskap'; + + @override + String get map_markers => 'Markörer'; + + @override + String get map_showSharedMarkers => 'Visa delade markörer'; + + @override + String get map_lastSeenTime => 'Senaste Visats Tid'; + + @override + String get map_sharedPin => 'Delad PIN'; + + @override + String get map_joinRoom => 'Gå med i rum'; + + @override + String get map_manageRepeater => 'Hantera Upprepare'; + + @override + String get mapCache_title => 'Offline Kartcache'; + + @override + String get mapCache_selectAreaFirst => 'Välj ett område att cachera först'; + + @override + String get mapCache_noTilesToDownload => + 'Inga kuber att ladda ner för detta område'; + + @override + String get mapCache_downloadTilesTitle => 'Ladda ner klick'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return 'Ladda ner $count kuber för offlineanvändning?'; + } + + @override + String get mapCache_downloadAction => 'Ladda ner'; + + @override + String mapCache_cachedTiles(int count) { + return 'Cache $count kuber'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return 'Cachelagda $downloaded klickark ($failed misslyckades)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => 'Rensa offline-cache'; + + @override + String get mapCache_clearOfflineCachePrompt => 'Ta bort alla cachemapplaner?'; + + @override + String get mapCache_offlineCacheCleared => 'Offline-cache rensad'; + + @override + String get mapCache_noAreaSelected => 'Ingen area markerad'; + + @override + String get mapCache_cacheArea => 'Cacheområde'; + + @override + String get mapCache_useCurrentView => 'Använd Aktuell Visning'; + + @override + String get mapCache_zoomRange => 'Zoombegränsning'; + + @override + String mapCache_estimatedTiles(int count) { + return 'Uppskattat antal klick: $count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return 'Ladda ner $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => 'Ladda ner klick'; + + @override + String get mapCache_clearCacheButton => 'Rensa Cache'; + + @override + String mapCache_failedDownloads(int count) { + return 'Misslyckade nedladdningar: $count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return 'N $north, S $south, E $east, W $west'; + } + + @override + String get time_justNow => 'Precis nu'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes min sedan'; + } + + @override + String time_hoursAgo(int hours) { + return '$hours timmar sedan'; + } + + @override + String time_daysAgo(int days) { + return '$days dagar sedan'; + } + + @override + String get time_hour => 'timme'; + + @override + String get time_hours => 'timmar'; + + @override + String get time_day => 'dag'; + + @override + String get time_days => 'dagar'; + + @override + String get time_week => 'vecka'; + + @override + String get time_weeks => 'veckor'; + + @override + String get time_month => 'månad'; + + @override + String get time_months => 'månader'; + + @override + String get time_minutes => 'minuter'; + + @override + String get time_allTime => 'Alla tider'; + + @override + String get dialog_disconnect => 'Koppla från'; + + @override + String get dialog_disconnectConfirm => + 'Är du säker på att du vill koppla från enheten?'; + + @override + String get login_repeaterLogin => 'Återuppta Inloggning'; + + @override + String get login_roomLogin => 'Rum Inloggning'; + + @override + String get login_password => 'Lösenord'; + + @override + String get login_enterPassword => 'Ange lösenord'; + + @override + String get login_savePassword => 'Spara lösenord'; + + @override + String get login_savePasswordSubtitle => + 'Lösenord kommer att lagras säkert på enheten.'; + + @override + String get login_repeaterDescription => + 'Ange återuppspelarens lösenord för att komma åt inställningar och status.'; + + @override + String get login_roomDescription => + 'Ange rummets lösenord för att komma åt inställningar och status.'; + + @override + String get login_routing => 'Ruttning'; + + @override + String get login_routingMode => 'Ruttläge'; + + @override + String get login_autoUseSavedPath => 'Automatisk (använd sparad sökväg)'; + + @override + String get login_forceFloodMode => 'Tvinga Översvämningsläge'; + + @override + String get login_managePaths => 'Hantera Sökvägar'; + + @override + String get login_login => 'Logga in'; + + @override + String login_attempt(int current, int max) { + return 'Försök $current/$max'; + } + + @override + String login_failed(String error) { + return 'Inloggning misslyckades: $error'; + } + + @override + String get common_reload => 'Ladda om'; + + @override + String get common_clear => 'Rensa'; + + @override + String path_currentPath(String path) { + return 'Nuvarande sökväg: $path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return 'Använda $count $_temp0 sökväg'; + } + + @override + String get path_enterCustomPath => 'Ange anpassad sökväg'; + + @override + String get path_currentPathLabel => 'Nuvarande sökväg'; + + @override + String get path_hexPrefixInstructions => + 'Ange 2-tecknets hex-prefett för varje hopp, åtskilda med komma.'; + + @override + String get path_hexPrefixExample => + 'Exempel: A1,F2,3C (varje nod använder det första bytet av sitt publika nyckel)'; + + @override + String get path_labelHexPrefixes => 'Hexprefixer'; + + @override + String get path_helperMaxHops => + 'Max 64 hopp. Varje prefix är 2 hex-tecken (1 byte)'; + + @override + String get path_selectFromContacts => 'Välj istället från kontakter:'; + + @override + String get path_noRepeatersFound => + 'Inga återuppspelare eller rumsservrar hittades.'; + + @override + String get path_customPathsRequire => + 'Anpassade sökvägar kräver mellansteg som kan vidarebefordra meddelanden.'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return 'Ogiltiga hex-prefikser: $prefixes'; + } + + @override + String get path_tooLong => 'Sökvägen är för lång. Max 64 hopp tillåtna.'; + + @override + String get path_setPath => 'Ange Sökväg'; + + @override + String get repeater_management => 'Återuppspelarens Hantering'; + + @override + String get repeater_managementTools => 'Administrationsverktyg'; + + @override + String get repeater_status => 'Status'; + + @override + String get repeater_statusSubtitle => + 'Visa återspolningsstatus, statistik och grannar'; + + @override + String get repeater_telemetry => 'Telemetry'; + + @override + String get repeater_telemetrySubtitle => + 'Visa telemetri för sensorer och systemstatistik'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => 'Skicka kommandon till repetitorn'; + + @override + String get repeater_settings => 'Inställningar'; + + @override + String get repeater_settingsSubtitle => 'Konfigurera återspolarparametrar'; + + @override + String get repeater_statusTitle => 'Återspelsstatus'; + + @override + String get repeater_routingMode => 'Ruttläge'; + + @override + String get repeater_autoUseSavedPath => 'Automatisk (använd sparad sökväg)'; + + @override + String get repeater_forceFloodMode => 'Tvinga Översvämningsläge'; + + @override + String get repeater_pathManagement => 'Stigarhantering'; + + @override + String get repeater_refresh => 'Uppdatera'; + + @override + String get repeater_statusRequestTimeout => + 'Statusförfrågan gick inte att hämta.'; + + @override + String repeater_errorLoadingStatus(String error) { + return 'Fel vid inläsning av status: $error'; + } + + @override + String get repeater_systemInformation => 'Systeminformation'; + + @override + String get repeater_battery => 'Batteri'; + + @override + String get repeater_clockAtLogin => 'Klocka (vid inloggning)'; + + @override + String get repeater_uptime => 'Tillgänglighet'; + + @override + String get repeater_queueLength => 'Köans längd'; + + @override + String get repeater_debugFlags => 'Felsökningsflaggor'; + + @override + String get repeater_radioStatistics => 'Radiostatistik'; + + @override + String get repeater_lastRssi => 'Senaste RSSI'; + + @override + String get repeater_lastSnr => 'Sista SNR'; + + @override + String get repeater_noiseFloor => 'Ljudnivå'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => 'Paketstatistik'; + + @override + String get repeater_sent => 'Skickat'; + + @override + String get repeater_received => 'Mottaget'; + + @override + String get repeater_duplicates => 'Dubbletter'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days dagar $hours timmar $minutes minuter $seconds sekunder'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return 'Totalt: $total, Översvämning: $flood, Direkt: $direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return 'Totalt: $total, Översvämning: $flood, Direkt: $direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return 'Översvämning: $flood, Direkt: $direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return 'Totalt: $total'; + } + + @override + String get repeater_settingsTitle => 'Återuppspelarens Inställningar'; + + @override + String get repeater_basicSettings => 'Grundinställningar'; + + @override + String get repeater_repeaterName => 'Upprepare Namn'; + + @override + String get repeater_repeaterNameHelper => 'Visa namn för denna återupprepare'; + + @override + String get repeater_adminPassword => 'Adminlösenord'; + + @override + String get repeater_adminPasswordHelper => 'Fullständig åtkomstlösenord'; + + @override + String get repeater_guestPassword => 'Gästlösenhet'; + + @override + String get repeater_guestPasswordHelper => 'Läs-skyddspassord'; + + @override + String get repeater_radioSettings => 'Radioinställningar'; + + @override + String get repeater_frequencyMhz => 'Frekvens (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Effekt'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => 'Bandbredd'; + + @override + String get repeater_spreadingFactor => 'Spreadingfaktor'; + + @override + String get repeater_codingRate => 'Kodningsgrad'; + + @override + String get repeater_locationSettings => 'Platsinställningar'; + + @override + String get repeater_latitude => 'Latitud'; + + @override + String get repeater_latitudeHelper => 'Decimalgrader (t.ex. 37.7749)'; + + @override + String get repeater_longitude => 'Längdgrad'; + + @override + String get repeater_longitudeHelper => 'Decimalgrader (t.ex. -122.4194)'; + + @override + String get repeater_features => 'Funktioner'; + + @override + String get repeater_packetForwarding => 'Paketväxling'; + + @override + String get repeater_packetForwardingSubtitle => + 'Aktivera återuppspelaren för att vidarebefordra paket'; + + @override + String get repeater_guestAccess => 'Gäståtkomst'; + + @override + String get repeater_guestAccessSubtitle => + 'Tillåt läsbehörigheter för gäster.'; + + @override + String get repeater_privacyMode => 'Privatläge'; + + @override + String get repeater_privacyModeSubtitle => 'Dölj namn/plats i annonser'; + + @override + String get repeater_advertisementSettings => 'Annonsinställningar'; + + @override + String get repeater_localAdvertInterval => 'Lokalt Annonsintervall'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes minuter'; + } + + @override + String get repeater_floodAdvertInterval => + 'Översvämnadsannonsens tidsintervall'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours timmar'; + } + + @override + String get repeater_encryptedAdvertInterval => 'Krypterad Annonsintervall'; + + @override + String get repeater_dangerZone => 'Faraområde'; + + @override + String get repeater_rebootRepeater => 'Starta Återuppspelaren'; + + @override + String get repeater_rebootRepeaterSubtitle => 'Starta om repeternheten'; + + @override + String get repeater_rebootRepeaterConfirm => + 'Är du säker på att du vill starta om denna repeater?'; + + @override + String get repeater_regenerateIdentityKey => 'Generera Identitetsknyckel'; + + @override + String get repeater_regenerateIdentityKeySubtitle => + 'Generera ny publik/privat nyckelpar'; + + @override + String get repeater_regenerateIdentityKeyConfirm => + 'Detta kommer att generera en ny identitet för återspelaren. Fortsätta?'; + + @override + String get repeater_eraseFileSystem => 'Radera Filsystem'; + + @override + String get repeater_eraseFileSystemSubtitle => + 'Formatera återspelsfilsystemet'; + + @override + String get repeater_eraseFileSystemConfirm => + 'VARNING: Detta kommer att radera all data på repeatern. Detta kan inte ångras!'; + + @override + String get repeater_eraseSerialOnly => + 'Rensa är endast tillgängligt via seriell konsol.'; + + @override + String repeater_commandSent(String command) { + return 'Kommandot skickades: $command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return 'Fel vid skickande av kommando: $error'; + } + + @override + String get repeater_confirm => 'Bekräfta'; + + @override + String get repeater_settingsSaved => + 'Inställningarna sparades framgångsrikt.'; + + @override + String repeater_errorSavingSettings(String error) { + return 'Fel vid sparande av inställningar: $error'; + } + + @override + String get repeater_refreshBasicSettings => + 'Återställ Grundläggande Inställningar'; + + @override + String get repeater_refreshRadioSettings => 'Återställ Radiosinställningar'; + + @override + String get repeater_refreshTxPower => 'Återställ TX-effekt'; + + @override + String get repeater_refreshLocationSettings => + 'Uppdatera Lokationsinställningar'; + + @override + String get repeater_refreshPacketForwarding => 'Återställ Paketväxling'; + + @override + String get repeater_refreshGuestAccess => 'Återställ Gäståtkomst'; + + @override + String get repeater_refreshPrivacyMode => 'Återställ Sekretessläge'; + + @override + String get repeater_refreshAdvertisementSettings => + 'Återställ Annonsinställningar'; + + @override + String repeater_refreshed(String label) { + return '$label har uppdaterats'; + } + + @override + String repeater_errorRefreshing(String label) { + return 'Fel vid uppdatering av $label'; + } + + @override + String get repeater_cliTitle => 'Återuppspelaren CLI'; + + @override + String get repeater_debugNextCommand => 'Felsök Nästa Kommando'; + + @override + String get repeater_commandHelp => 'Hjälp'; + + @override + String get repeater_clearHistory => 'Rensa Historik'; + + @override + String get repeater_noCommandsSent => 'Inga kommandon skickats ännu'; + + @override + String get repeater_typeCommandOrUseQuick => + 'Skriv en kommando nedan eller använd snabba kommandon'; + + @override + String get repeater_enterCommandHint => 'Ange kommando...'; + + @override + String get repeater_previousCommand => 'Tidigare kommando'; + + @override + String get repeater_nextCommand => 'Nästa kommando'; + + @override + String get repeater_enterCommandFirst => 'Ange en kommando först'; + + @override + String get repeater_cliCommandFrameTitle => 'Kommandofönster'; + + @override + String repeater_cliCommandError(String error) { + return 'Fel: $error'; + } + + @override + String get repeater_cliQuickGetName => 'Hämta namn'; + + @override + String get repeater_cliQuickGetRadio => 'Få Radio'; + + @override + String get repeater_cliQuickGetTx => 'Hämta TX'; + + @override + String get repeater_cliQuickNeighbors => 'Grannar'; + + @override + String get repeater_cliQuickVersion => 'Version'; + + @override + String get repeater_cliQuickAdvertise => 'Annonsera'; + + @override + String get repeater_cliQuickClock => 'Klocka'; + + @override + String get repeater_cliHelpAdvert => 'Skickar ett annonspaket'; + + @override + String get repeater_cliHelpReboot => + 'Startar om enheten. (notera, du får kanske \'Timeout\' vilket är normalt)'; + + @override + String get repeater_cliHelpClock => 'Visar aktuell tid per enhetens klocka.'; + + @override + String get repeater_cliHelpPassword => + 'Ställer in ett nytt administratörslösenord för enheten.'; + + @override + String get repeater_cliHelpVersion => + 'Visar enhetsversion och firmwarebyggnadsdatum.'; + + @override + String get repeater_cliHelpClearStats => + 'Återställer olika statistikräknare till noll.'; + + @override + String get repeater_cliHelpSetAf => 'Ställer in lufttidsfaktor.'; + + @override + String get repeater_cliHelpSetTx => + 'Ställer LoRa-sändningseffekten i dBm. (starta om för att tillämpa)'; + + @override + String get repeater_cliHelpSetRepeat => + 'Aktiverar eller inaktiverar återuppspelarens roll för denna nod.'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(Rumserver) Om \'på\', så tillåts login med tomt lösenord, men kan inte Posta till rummet. (bara läsa).'; + + @override + String get repeater_cliHelpSetFloodMax => + 'Ställer in det maximala antalet hopp för inkommande översvämning (om >= max, skickas inte paketet).'; + + @override + String get repeater_cliHelpSetIntThresh => + 'Ställer Interferensgränsen (i dB). Standardvärdet är 14. Ställ in den på 0 för att inaktivera detektion av kanalinterferens.'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + 'Ställer in intervallet för att återställa Auto Gain-kontrollen. Ställ in till 0 för att inaktivera.'; + + @override + String get repeater_cliHelpSetMultiAcks => + 'Aktiverar eller inaktiverar funktionen \'dubbla ACKs\'.'; + + @override + String get repeater_cliHelpSetAdvertInterval => + 'Ställer in tidsintervallen i minuter för att skicka ett lokalt (utan-hopp) annonseringspaket. Ställs till 0 för att inaktivera.'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + 'Ställer in tidsintervallen i timmar för att skicka ett flödesannonspaket. Ställ in på 0 för att inaktivera.'; + + @override + String get repeater_cliHelpSetGuestPassword => + 'Ställer in/uppdaterar gästlösenordet. (för återvändare kan gästloggar skicka \"Get Stats\"-förfrågan)'; + + @override + String get repeater_cliHelpSetName => 'Ställer in annonstexterna namn.'; + + @override + String get repeater_cliHelpSetLat => + 'Ställer in annonskartans latitud. (decimalgrader)'; + + @override + String get repeater_cliHelpSetLon => + 'Ställer in annonskartans longitud (decimalgrader).'; + + @override + String get repeater_cliHelpSetRadio => + 'Ställer helt nya radioparametrar och sparar dem i inställningar. Kräver en \"omstart\" för att tillämpa.'; + + @override + String get repeater_cliHelpSetRxDelay => + 'Ställer (experimentell) basvärde (måste vara > 1 för effekt) för att applicera en liten fördröjning på mottagna paket, baserat på signalstyrka/poäng. Ställ in på 0 för att inaktivera.'; + + @override + String get repeater_cliHelpSetTxDelay => + 'Ställer in en faktor som multipliceras med tid på luft för en översvämningsläge-paket och med ett slumpmässigt slot-system för att fördröja dess vidarebefordran (för att minska risken för kollisioner).'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + 'Samma som txdelay, men för att applicera en slumpmässig fördröjning vid vidarebefordran av direktlägespaket.'; + + @override + String get repeater_cliHelpSetBridgeEnabled => 'Aktivera/Inaktivera brygga.'; + + @override + String get repeater_cliHelpSetBridgeDelay => + 'Ställ in fördröjning innan paket åter sänder.'; + + @override + String get repeater_cliHelpSetBridgeSource => + 'Välj om bron ska återända mottagna paket eller sända paket.'; + + @override + String get repeater_cliHelpSetBridgeBaud => + 'Ställ baudgränsen för rs232-bryggarna.'; + + @override + String get repeater_cliHelpSetBridgeSecret => + 'Ställ bro-hemlighet för espnow-broar.'; + + @override + String get repeater_cliHelpSetAdcMultiplier => + 'Ställer in anpassad faktor för att justera rapporterad batterispänning (endast stödd på utvalda kort).'; + + @override + String get repeater_cliHelpTempRadio => + 'Ställer temporära radioparametrar för det angivna antalet minuter, vilket återgår till de ursprungliga radioparametrarna efteråt. (sparar inte i inställningar).'; + + @override + String get repeater_cliHelpSetPerm => + 'Modifierar ACL. Tar bort matchande post (genom pubkey-prefiks) om \"permissions\" är noll. Lägger till ny post om pubkey-hex är full längd och inte redan finns i ACL. Uppdaterar posten genom matchande pubkey-prefiks. Tillståndsbiten varierar per firmware-roll, men de låga 2 bitarna är: 0 (Gäst), 1 (endast läsa), 2 (läs- och skrivskydd), 3 (administratör).'; + + @override + String get repeater_cliHelpGetBridgeType => + 'Får brotyperna ingen, rs232, espnow'; + + @override + String get repeater_cliHelpLogStart => 'Starta paketloggning till filsystem.'; + + @override + String get repeater_cliHelpLogStop => 'Stoppar paketloggning till filsystem.'; + + @override + String get repeater_cliHelpLogErase => + 'Raderar pakets loggar från filsystemet.'; + + @override + String get repeater_cliHelpNeighbors => + 'Visar en lista över andra repeaternoder som hörts via noll-hop-annonser. Varje rad är id-prefix-hex:tidsstämpel:snr-g撮-4'; + + @override + String get repeater_cliHelpNeighborRemove => + 'Tar bort det första matchande inlägget (genom pubkey-prefiks (hex)) från grannlistan.'; + + @override + String get repeater_cliHelpRegion => + '(Serien endast) Listar alla definierade regioner och aktuella översvämningsbehörigheter.'; + + @override + String get repeater_cliHelpRegionLoad => + 'MEDDELANDE: detta är ett specialkommando med flera kommandon. Varje efterföljande kommando är ett regionsnamn (indenterat med blanksteg för att indikera en hierarkisk relation, med minst ett blanksteg). Avslutas genom att skicka en tom rad/kommando.'; + + @override + String get repeater_cliHelpRegionGet => + 'Söker efter region med given namnprefiks (eller \"\" för det globala scopet). Svarar med \"-> regionnamn (föräldernamn) \'F\'\"'; + + @override + String get repeater_cliHelpRegionPut => + 'Lägger till eller uppdaterar en regionsdefinition med det angivna namnet.'; + + @override + String get repeater_cliHelpRegionRemove => + 'Tar bort en regionsdefinition med det angivna namnet. (måste matcha exakt och inte ha några barnregioner)'; + + @override + String get repeater_cliHelpRegionAllowf => + 'Ställer \'Flöde\'-behörighet för det angivna området. (\'\' för det globala/gamla scopet)'; + + @override + String get repeater_cliHelpRegionDenyf => + 'Tar bort \'F\'lood-behörigheten för det angivna området. (OBS: rekommenderas inte att använda detta i detta skede på den globala/gamla omfattningen!!).'; + + @override + String get repeater_cliHelpRegionHome => + 'Svarar med den aktuella \'hem\'-regionen. (Notera att detta ännu inte har tillämpats, reserverat för framtida användning).'; + + @override + String get repeater_cliHelpRegionHomeSet => 'Ställer in \'hemregionen\'.'; + + @override + String get repeater_cliHelpRegionSave => + 'Sparar regionlistan/kartan till lagring.'; + + @override + String get repeater_cliHelpGps => + 'Visar GPS-status. Om GPS är avstängd svarar den endast med \"av\", annars svarar den med \"på\", status, fix, antal satelliter.'; + + @override + String get repeater_cliHelpGpsOnOff => + 'Aktiverar/inaktiverar GPS-strömsättningen.'; + + @override + String get repeater_cliHelpGpsSync => + 'Synkroniserar nätverks tid med GPS-klockan.'; + + @override + String get repeater_cliHelpGpsSetLoc => + 'Ställer nodens position till GPS-koordinater och sparar inställningar.'; + + @override + String get repeater_cliHelpGpsAdvert => + 'Ger platsannonskonfigurationen för noden:\n- ingen: inkludera inte plats i annonser\n- dela: dela gps-plats (från SensorManager)\n- inställningar: annonsera platsen som sparats i inställningar'; + + @override + String get repeater_cliHelpGpsAdvertSet => + 'Ställer in annonsplatskonfiguration.'; + + @override + String get repeater_commandsListTitle => 'Inställningslista'; + + @override + String get repeater_commandsListNote => + 'OBS: för de olika \"set ...\" -kommandon finns det även ett \"get ...\" -kommando.'; + + @override + String get repeater_general => 'Allmänt'; + + @override + String get repeater_settingsCategory => 'Inställningar'; + + @override + String get repeater_bridge => 'Bro'; + + @override + String get repeater_logging => 'Logga'; + + @override + String get repeater_neighborsRepeaterOnly => 'Grannar (Endast återspelare)'; + + @override + String get repeater_regionManagementRepeaterOnly => + 'Regionhantering (endast återuppspelare)'; + + @override + String get repeater_regionNote => + 'Regionkommandon har införts för att hantera regiondefinitioner och behörigheter.'; + + @override + String get repeater_gpsManagement => 'GPS Hantering'; + + @override + String get repeater_gpsNote => + 'GPS-kommando har introducerats för att hantera platsrelaterade ämnen.'; + + @override + String get telemetry_receivedData => 'Mottagen Telemetridata'; + + @override + String get telemetry_requestTimeout => 'Telemetryförfrågan gick ut.'; + + @override + String telemetry_errorLoading(String error) { + return 'Fel vid laddning av telemetri: $error'; + } + + @override + String get telemetry_noData => 'Inga telemetridata tillgängliga.'; + + @override + String telemetry_channelTitle(int channel) { + return 'Kanal $channel'; + } + + @override + String get telemetry_batteryLabel => 'Batteri'; + + @override + String get telemetry_voltageLabel => 'Spänning'; + + @override + String get telemetry_mcuTemperatureLabel => 'MCU Temperatur'; + + @override + String get telemetry_temperatureLabel => 'Temperatur'; + + @override + String get telemetry_currentLabel => 'Aktuell'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => 'Paketväg'; + + @override + String get channelPath_viewMap => 'Visa karta'; + + @override + String get channelPath_otherObservedPaths => 'Övriga observerade stigar'; + + @override + String get channelPath_repeaterHops => 'Återupptagningssteg'; + + @override + String get channelPath_noHopDetails => + 'Detaljer för denna paket är inte angivna.'; + + @override + String get channelPath_messageDetails => 'Meddelandets detaljer'; + + @override + String get channelPath_senderLabel => 'Avsändare'; + + @override + String get channelPath_timeLabel => 'Tid'; + + @override + String get channelPath_repeatsLabel => 'Upprepa'; + + @override + String channelPath_pathLabel(int index) { + return 'Sökväg $index'; + } + + @override + String get channelPath_observedLabel => 'Observerat'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return 'Observerad bana $index • $hops'; + } + + @override + String get channelPath_noLocationData => 'Ingen platsdata'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month kl. $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => 'Okänt'; + + @override + String get channelPath_floodPath => 'Översvämning'; + + @override + String get channelPath_directPath => 'Direkt'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 av $total hopp'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '$observed av $total hopp'; + } + + @override + String get channelPath_mapTitle => 'Sökvägskarta'; + + @override + String get channelPath_noRepeaterLocations => + 'Inga återupprepningsplatser finns tillgängliga för denna väg.'; + + @override + String channelPath_primaryPath(int index) { + return 'Sökväg $index (Primär)'; + } + + @override + String get channelPath_pathLabelTitle => 'Sökväg'; + + @override + String get channelPath_observedPathHeader => 'Observerad Sökväg'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => + 'Inga hoppdetaljer finns tillgängliga för detta paket.'; + + @override + String get channelPath_unknownRepeater => 'Okänt Upprepare'; + + @override + String get listFilter_tooltip => 'Filtrera och sortera'; + + @override + String get listFilter_sortBy => 'Sortera efter'; + + @override + String get listFilter_latestMessages => 'Senaste meddelanden'; + + @override + String get listFilter_heardRecently => 'Hörts nyligen'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => 'Filteralternativ'; + + @override + String get listFilter_all => 'Alla'; + + @override + String get listFilter_users => 'Användare'; + + @override + String get listFilter_repeaters => 'Upprepare'; + + @override + String get listFilter_roomServers => 'Rumservrar'; + + @override + String get listFilter_unreadOnly => 'Endast oinlästa'; + + @override + String get listFilter_newGroup => 'Ny grupp'; +} diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart new file mode 100644 index 0000000..e5b5a9f --- /dev/null +++ b/lib/l10n/app_localizations_zh.dart @@ -0,0 +1,2263 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Chinese (`zh`). +class AppLocalizationsZh extends AppLocalizations { + AppLocalizationsZh([String locale = 'zh']) : super(locale); + + @override + String get appTitle => 'MeshCore Open'; + + @override + String get nav_contacts => '联系人'; + + @override + String get nav_channels => '频道'; + + @override + String get nav_map => '地图'; + + @override + String get common_cancel => '取消'; + + @override + String get common_connect => '连接'; + + @override + String get common_unknownDevice => '未知设备'; + + @override + String get common_save => '保存'; + + @override + String get common_delete => '删除'; + + @override + String get common_close => '关闭'; + + @override + String get common_edit => '编辑'; + + @override + String get common_add => '添加'; + + @override + String get common_settings => '设置'; + + @override + String get common_disconnect => '断开'; + + @override + String get common_connected => '已连接'; + + @override + String get common_disconnected => '断开'; + + @override + String get common_create => '创建'; + + @override + String get common_continue => '继续'; + + @override + String get common_share => '分享'; + + @override + String get common_copy => '复制'; + + @override + String get common_retry => '重试'; + + @override + String get common_hide => '隐藏'; + + @override + String get common_remove => '删除'; + + @override + String get common_enable => '启用'; + + @override + String get common_disable => '禁用'; + + @override + String get common_reboot => '重启'; + + @override + String get common_loading => '正在加载...'; + + @override + String get common_notAvailable => '—'; + + @override + String common_voltageValue(String volts) { + return '$volts V'; + } + + @override + String common_percentValue(int percent) { + return '$percent%'; + } + + @override + String get scanner_title => 'MeshCore Open'; + + @override + String get scanner_scanning => '扫描设备…'; + + @override + String get scanner_connecting => '连接中...'; + + @override + String get scanner_disconnecting => '断开中...'; + + @override + String get scanner_notConnected => '未连接'; + + @override + String scanner_connectedTo(String deviceName) { + return '已连接至 $deviceName'; + } + + @override + String get scanner_searchingDevices => '搜索 MeshCore 设备...'; + + @override + String get scanner_tapToScan => '点击扫描以查找MeshCore设备'; + + @override + String scanner_connectionFailed(String error) { + return '连接失败:$error'; + } + + @override + String get scanner_stop => '停止'; + + @override + String get scanner_scan => '扫描'; + + @override + String get device_quickSwitch => '快速切换'; + + @override + String get device_meshcore => 'MeshCore'; + + @override + String get settings_title => '设置'; + + @override + String get settings_deviceInfo => '设备信息'; + + @override + String get settings_appSettings => '应用设置'; + + @override + String get settings_appSettingsSubtitle => '通知、消息和地图偏好'; + + @override + String get settings_nodeSettings => '节点设置'; + + @override + String get settings_nodeName => '节点名称'; + + @override + String get settings_nodeNameNotSet => '未设置'; + + @override + String get settings_nodeNameHint => '请输入节点名称'; + + @override + String get settings_nodeNameUpdated => '姓名已更新'; + + @override + String get settings_radioSettings => '无线设置'; + + @override + String get settings_radioSettingsSubtitle => '频率,功率,扩展因子'; + + @override + String get settings_radioSettingsUpdated => '射频设置已更新'; + + @override + String get settings_location => '位置'; + + @override + String get settings_locationSubtitle => 'GPS坐标'; + + @override + String get settings_locationUpdated => '位置已更新'; + + @override + String get settings_locationBothRequired => '请输入纬度和经度。'; + + @override + String get settings_locationInvalid => '无效的纬度或经度。'; + + @override + String get settings_latitude => '纬度'; + + @override + String get settings_longitude => '经度'; + + @override + String get settings_privacyMode => '隐私模式'; + + @override + String get settings_privacyModeSubtitle => '隐藏在广告中的姓名/位置'; + + @override + String get settings_privacyModeToggle => '开启隐私模式以隐藏您的姓名和位置在广告中的显示。'; + + @override + String get settings_privacyModeEnabled => '隐私模式已启用'; + + @override + String get settings_privacyModeDisabled => '隐私模式已禁用'; + + @override + String get settings_actions => '操作'; + + @override + String get settings_sendAdvertisement => '发送广告'; + + @override + String get settings_sendAdvertisementSubtitle => '现在已广播'; + + @override + String get settings_advertisementSent => '广告已发送'; + + @override + String get settings_syncTime => '同步时间'; + + @override + String get settings_syncTimeSubtitle => '将设备时钟设置为手机时间'; + + @override + String get settings_timeSynchronized => '时间同步'; + + @override + String get settings_refreshContacts => '刷新联系人'; + + @override + String get settings_refreshContactsSubtitle => '从设备重新加载联系人列表'; + + @override + String get settings_rebootDevice => '重启设备'; + + @override + String get settings_rebootDeviceSubtitle => '重启 MeshCore 设备'; + + @override + String get settings_rebootDeviceConfirm => '您确定要重启设备吗?您将会断开连接。'; + + @override + String get settings_debug => '调试'; + + @override + String get settings_bleDebugLog => '蓝牙调试日志'; + + @override + String get settings_bleDebugLogSubtitle => '蓝牙命令、响应和原始数据'; + + @override + String get settings_appDebugLog => '应用调试日志'; + + @override + String get settings_appDebugLogSubtitle => '应用调试消息'; + + @override + String get settings_about => '关于'; + + @override + String settings_aboutVersion(String version) { + return 'MeshCore Open v$version'; + } + + @override + String get settings_aboutLegalese => '2024 MeshCore 开放源代码项目'; + + @override + String get settings_aboutDescription => + '一个开源的 Flutter 客户端,用于 MeshCore LoRa 网状网络设备。'; + + @override + String get settings_infoName => '姓名'; + + @override + String get settings_infoId => 'ID'; + + @override + String get settings_infoStatus => '状态'; + + @override + String get settings_infoBattery => '电池'; + + @override + String get settings_infoPublicKey => '公钥'; + + @override + String get settings_infoContactsCount => '联系人数量'; + + @override + String get settings_infoChannelCount => '频道数量'; + + @override + String get settings_presets => '预设'; + + @override + String get settings_preset915Mhz => '915 MHz'; + + @override + String get settings_preset868Mhz => '868 MHz'; + + @override + String get settings_preset433Mhz => '433 MHz'; + + @override + String get settings_frequency => '频率 (MHz)'; + + @override + String get settings_frequencyHelper => '300.0 - 2500.0'; + + @override + String get settings_frequencyInvalid => '无效频率 (300-2500 MHz)'; + + @override + String get settings_bandwidth => '带宽'; + + @override + String get settings_spreadingFactor => '扩散因子'; + + @override + String get settings_codingRate => '编码速率'; + + @override + String get settings_txPower => 'TX Power (dBm)'; + + @override + String get settings_txPowerHelper => '0 - 22'; + + @override + String get settings_txPowerInvalid => '无效的 TX 电功率 (0-22 dBm)'; + + @override + String get settings_longRange => '远距离'; + + @override + String get settings_fastSpeed => '快速速度'; + + @override + String settings_error(String message) { + return '错误:$message'; + } + + @override + String get appSettings_title => '应用设置'; + + @override + String get appSettings_appearance => '外观'; + + @override + String get appSettings_theme => '主题'; + + @override + String get appSettings_themeSystem => '系统默认'; + + @override + String get appSettings_themeLight => '光'; + + @override + String get appSettings_themeDark => '深色'; + + @override + String get appSettings_language => '语言'; + + @override + String get appSettings_languageSystem => '系统默认'; + + @override + String get appSettings_languageEn => 'English'; + + @override + String get appSettings_languageFr => 'Français'; + + @override + String get appSettings_languageEs => 'Español'; + + @override + String get appSettings_languageDe => 'Deutsch'; + + @override + String get appSettings_languagePl => 'Polski'; + + @override + String get appSettings_languageSl => 'Slovenščina'; + + @override + String get appSettings_languagePt => 'Português'; + + @override + String get appSettings_languageIt => 'Italiano'; + + @override + String get appSettings_languageZh => '中文'; + + @override + String get appSettings_languageSv => 'Svenska'; + + @override + String get appSettings_languageNl => 'Nederlands'; + + @override + String get appSettings_languageSk => 'Slovenčina'; + + @override + String get appSettings_languageBg => 'Български'; + + @override + String get appSettings_notifications => '通知'; + + @override + String get appSettings_enableNotifications => '启用通知'; + + @override + String get appSettings_enableNotificationsSubtitle => '接收消息和广告的通知'; + + @override + String get appSettings_notificationPermissionDenied => '通知权限被拒绝'; + + @override + String get appSettings_notificationsEnabled => '通知已启用'; + + @override + String get appSettings_notificationsDisabled => '通知已关闭'; + + @override + String get appSettings_messageNotifications => '消息通知'; + + @override + String get appSettings_messageNotificationsSubtitle => '显示收到新消息时的通知'; + + @override + String get appSettings_channelMessageNotifications => '频道消息通知'; + + @override + String get appSettings_channelMessageNotificationsSubtitle => '显示接收频道消息时的通知'; + + @override + String get appSettings_advertisementNotifications => '广告通知'; + + @override + String get appSettings_advertisementNotificationsSubtitle => '显示当新节点被发现时通知'; + + @override + String get appSettings_messaging => '消息'; + + @override + String get appSettings_clearPathOnMaxRetry => '清除最大重试路径'; + + @override + String get appSettings_clearPathOnMaxRetrySubtitle => '重置联系人路径,在5次发送失败尝试后'; + + @override + String get appSettings_pathsWillBeCleared => '路径将在5次失败重试后清除'; + + @override + String get appSettings_pathsWillNotBeCleared => '路径不会自动清理'; + + @override + String get appSettings_autoRouteRotation => '自动路径旋转'; + + @override + String get appSettings_autoRouteRotationSubtitle => '在最佳路径和洪水模式之间切换'; + + @override + String get appSettings_autoRouteRotationEnabled => '自动路径轮换已启用'; + + @override + String get appSettings_autoRouteRotationDisabled => '自动路径轮换已禁用'; + + @override + String get appSettings_battery => '电池'; + + @override + String get appSettings_batteryChemistry => '电池化学'; + + @override + String appSettings_batteryChemistryPerDevice(String deviceName) { + return '设置每个设备 ($deviceName)'; + } + + @override + String get appSettings_batteryChemistryConnectFirst => '连接设备以选择'; + + @override + String get appSettings_batteryNmc => '18650 NMC (3.0-4.2V)'; + + @override + String get appSettings_batteryLifepo4 => '磷酸铁锂 (2.6-3.65V)'; + + @override + String get appSettings_batteryLipo => 'LiPo (3.0-4.2V)'; + + @override + String get appSettings_mapDisplay => '地图显示'; + + @override + String get appSettings_showRepeaters => '显示循环器'; + + @override + String get appSettings_showRepeatersSubtitle => '在地图上显示重复节点'; + + @override + String get appSettings_showChatNodes => '显示聊天节点'; + + @override + String get appSettings_showChatNodesSubtitle => '在地图上显示聊天节点'; + + @override + String get appSettings_showOtherNodes => '显示其他节点'; + + @override + String get appSettings_showOtherNodesSubtitle => '显示其他节点类型在地图上'; + + @override + String get appSettings_timeFilter => '时间筛选'; + + @override + String get appSettings_timeFilterShowAll => '显示所有节点'; + + @override + String appSettings_timeFilterShowLast(int hours) { + return '显示来自过去 $hours 小时的节点'; + } + + @override + String get appSettings_mapTimeFilter => '地图时间筛选'; + + @override + String get appSettings_showNodesDiscoveredWithin => '显示发现的节点在:'; + + @override + String get appSettings_allTime => '所有时间'; + + @override + String get appSettings_lastHour => '最后小时'; + + @override + String get appSettings_last6Hours => '最后6小时'; + + @override + String get appSettings_last24Hours => '最后24小时'; + + @override + String get appSettings_lastWeek => '上周'; + + @override + String get appSettings_offlineMapCache => '离线地图缓存'; + + @override + String get appSettings_noAreaSelected => '未选择任何区域'; + + @override + String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { + return '选中的区域(缩放至 $minZoom - $maxZoom)'; + } + + @override + String get appSettings_debugCard => '调试'; + + @override + String get appSettings_appDebugLogging => '应用调试日志'; + + @override + String get appSettings_appDebugLoggingSubtitle => '记录应用调试消息以供故障排除'; + + @override + String get appSettings_appDebugLoggingEnabled => '应用调试日志已启用'; + + @override + String get appSettings_appDebugLoggingDisabled => '应用调试日志已禁用'; + + @override + String get contacts_title => '联系人'; + + @override + String get contacts_noContacts => '还没有联系人'; + + @override + String get contacts_contactsWillAppear => '设备会广播时,联系人会显示'; + + @override + String get contacts_searchContacts => '搜索联系人...'; + + @override + String get contacts_noUnreadContacts => '未读联系人'; + + @override + String get contacts_noContactsFound => '未找到任何联系人或群组'; + + @override + String get contacts_deleteContact => '删除联系人'; + + @override + String contacts_removeConfirm(String contactName) { + return '从联系人中删除 $contactName 吗?'; + } + + @override + String get contacts_manageRepeater => '管理重复项'; + + @override + String get contacts_roomLogin => '房间登录'; + + @override + String get contacts_openChat => '打开聊天'; + + @override + String get contacts_editGroup => '编辑组'; + + @override + String get contacts_deleteGroup => '删除分组'; + + @override + String contacts_deleteGroupConfirm(String groupName) { + return '删除\"$groupName\"?'; + } + + @override + String get contacts_newGroup => '新组'; + + @override + String get contacts_groupName => '组名'; + + @override + String get contacts_groupNameRequired => '组名不能为空'; + + @override + String contacts_groupAlreadyExists(String name) { + return '组“$name”已存在'; + } + + @override + String get contacts_filterContacts => '筛选联系人...'; + + @override + String get contacts_noContactsMatchFilter => '未找到匹配您的筛选条件的结果'; + + @override + String get contacts_noMembers => '没有会员'; + + @override + String get contacts_lastSeenNow => '最后一次登录时间现在'; + + @override + String contacts_lastSeenMinsAgo(int minutes) { + return '最后一次出现 $minutes 分前'; + } + + @override + String get contacts_lastSeenHourAgo => '最后一次出现前1小时'; + + @override + String contacts_lastSeenHoursAgo(int hours) { + return '最后一次出现 $hours 小时前'; + } + + @override + String get contacts_lastSeenDayAgo => '最后一次登录前一天'; + + @override + String contacts_lastSeenDaysAgo(int days) { + return '最后一次出现 $days 天前'; + } + + @override + String get channels_title => '频道'; + + @override + String get channels_noChannelsConfigured => '未配置任何频道'; + + @override + String get channels_addPublicChannel => '添加公开频道'; + + @override + String get channels_searchChannels => '搜索频道...'; + + @override + String get channels_noChannelsFound => '未找到任何频道'; + + @override + String channels_channelIndex(int index) { + return '频道 $index'; + } + + @override + String get channels_hashtagChannel => '话题频道'; + + @override + String get channels_public => '公开'; + + @override + String get channels_private => '私有'; + + @override + String get channels_publicChannel => '公开频道'; + + @override + String get channels_privateChannel => '私聊频道'; + + @override + String get channels_editChannel => '编辑频道'; + + @override + String get channels_deleteChannel => '删除频道'; + + @override + String channels_deleteChannelConfirm(String name) { + return '删除\"$name\"?此操作无法撤销。'; + } + + @override + String channels_channelDeleted(String name) { + return '频道“$name”已删除'; + } + + @override + String get channels_addChannel => '添加频道'; + + @override + String get channels_channelIndexLabel => '频道索引'; + + @override + String get channels_channelName => '频道名称'; + + @override + String get channels_usePublicChannel => '使用公共频道'; + + @override + String get channels_standardPublicPsk => '标准公钥共享密钥'; + + @override + String get channels_pskHex => 'PSK (十六进制)'; + + @override + String get channels_generateRandomPsk => '生成随机PSK'; + + @override + String get channels_enterChannelName => '请输入频道名称'; + + @override + String get channels_pskMustBe32Hex => 'PSK 必须是 32 个十六进制字符'; + + @override + String channels_channelAdded(String name) { + return '频道“$name”已添加'; + } + + @override + String channels_editChannelTitle(int index) { + return '编辑频道 $index'; + } + + @override + String get channels_smazCompression => 'SMAZ 压缩'; + + @override + String channels_channelUpdated(String name) { + return '频道“$name”已更新'; + } + + @override + String get channels_publicChannelAdded => '公共频道已添加'; + + @override + String get channels_sortBy => '按类型排序'; + + @override + String get channels_sortManual => '手动'; + + @override + String get channels_sortAZ => 'A-Z'; + + @override + String get channels_sortLatestMessages => '最新消息'; + + @override + String get channels_sortUnread => '未读'; + + @override + String get chat_noMessages => '目前还没有消息'; + + @override + String get chat_sendMessageToStart => '发送消息开始'; + + @override + String get chat_originalMessageNotFound => '找不到原始消息'; + + @override + String chat_replyingTo(String name) { + return '回复 $name'; + } + + @override + String chat_replyTo(String name) { + return '回复 $name'; + } + + @override + String get chat_location => '位置'; + + @override + String chat_sendMessageTo(String contactName) { + return '向$contactName发送消息'; + } + + @override + String get chat_typeMessage => '输入消息...'; + + @override + String chat_messageTooLong(int maxBytes) { + return '消息太长了(最大 $maxBytes 字节)。'; + } + + @override + String get chat_messageCopied => '消息已复制'; + + @override + String get chat_messageDeleted => '消息已删除'; + + @override + String get chat_retryingMessage => '重试'; + + @override + String chat_retryCount(int current, int max) { + return '重试 $current/$max'; + } + + @override + String get chat_sendGif => '发送GIF'; + + @override + String get chat_reply => '回复'; + + @override + String get chat_addReaction => '添加反应'; + + @override + String get chat_me => '我'; + + @override + String get emojiCategorySmileys => '表情符号'; + + @override + String get emojiCategoryGestures => '手势'; + + @override + String get emojiCategoryHearts => '心'; + + @override + String get emojiCategoryObjects => '对象'; + + @override + String get gifPicker_title => '选择一个 GIF'; + + @override + String get gifPicker_searchHint => '搜索GIF...'; + + @override + String get gifPicker_poweredBy => '由 GIPHY 提供支持'; + + @override + String get gifPicker_noGifsFound => '未找到 GIF 动画'; + + @override + String get gifPicker_failedLoad => 'GIF 加载失败'; + + @override + String get gifPicker_failedSearch => '搜索GIF失败'; + + @override + String get gifPicker_noInternet => '无网络连接'; + + @override + String get debugLog_appTitle => '应用调试日志'; + + @override + String get debugLog_bleTitle => '蓝牙调试日志'; + + @override + String get debugLog_copyLog => '复制日志'; + + @override + String get debugLog_clearLog => '清除日志'; + + @override + String get debugLog_copied => '调试日志已复制'; + + @override + String get debugLog_bleCopied => '蓝牙日志复制'; + + @override + String get debugLog_noEntries => '尚未生成调试日志'; + + @override + String get debugLog_enableInSettings => '启用应用调试日志记录设置'; + + @override + String get debugLog_frames => '帧'; + + @override + String get debugLog_rawLogRx => '原始日志-RX'; + + @override + String get debugLog_noBleActivity => '目前还没有蓝牙活动。'; + + @override + String debugFrame_length(int count) { + return '帧长度:$count 字节'; + } + + @override + String debugFrame_command(String value) { + return '命令:0x$value'; + } + + @override + String get debugFrame_textMessageHeader => '短信框'; + + @override + String debugFrame_destinationPubKey(String pubKey) { + return '- 目的地公钥:$pubKey'; + } + + @override + String debugFrame_timestamp(int timestamp) { + return '- 时间戳:$timestamp'; + } + + @override + String debugFrame_flags(String value) { + return '- 标志:0x$value'; + } + + @override + String debugFrame_textType(int type, String label) { + return '- 文本类型:$type ($label)'; + } + + @override + String get debugFrame_textTypeCli => 'CLI'; + + @override + String get debugFrame_textTypePlain => '简洁'; + + @override + String debugFrame_text(String text) { + return '- 文本:\"$text\"'; + } + + @override + String get debugFrame_hexDump => '十六进制数据'; + + @override + String get chat_pathManagement => '路径管理'; + + @override + String get chat_routingMode => '路由模式'; + + @override + String get chat_autoUseSavedPath => '自动(使用已保存路径)'; + + @override + String get chat_forceFloodMode => '强制洪水模式'; + + @override + String get chat_recentAckPaths => '最近的 ACK 路径 (点击以使用):'; + + @override + String get chat_pathHistoryFull => '路径历史已满。删除条目以添加新条目。'; + + @override + String get chat_hopSingular => '跳转'; + + @override + String get chat_hopPlural => '跳跃'; + + @override + String chat_hopsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '跳跃', + one: '跳跃', + ); + return '$count $_temp0'; + } + + @override + String get chat_successes => '成功'; + + @override + String get chat_removePath => '删除路径'; + + @override + String get chat_noPathHistoryYet => '还没有历史记录。\n发送消息以发现路径。'; + + @override + String get chat_pathActions => '路径操作:'; + + @override + String get chat_setCustomPath => '设置自定义路径'; + + @override + String get chat_setCustomPathSubtitle => '手动指定路由路径'; + + @override + String get chat_clearPath => '清除路径'; + + @override + String get chat_clearPathSubtitle => '强制下次发送时重新发现'; + + @override + String get chat_pathCleared => '路径已清除。下一条消息将重新发现路线。'; + + @override + String get chat_floodModeSubtitle => '使用应用栏中的路由切换开关'; + + @override + String get chat_floodModeEnabled => '防洪模式已启用。通过应用程序栏中的路由图标进行反转。'; + + @override + String get chat_fullPath => '完整路径'; + + @override + String get chat_pathDetailsNotAvailable => '路径详情尚未获取。请尝试发送消息以刷新。'; + + @override + String chat_pathSetHops(int hopCount, String status) { + String _temp0 = intl.Intl.pluralLogic( + hopCount, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '路径设置:$hopCount $_temp0 - $status'; + } + + @override + String get chat_pathSavedLocally => '已本地保存。连接以同步。'; + + @override + String get chat_pathDeviceConfirmed => '设备已确认。'; + + @override + String get chat_pathDeviceNotConfirmed => '设备尚未确认。'; + + @override + String get chat_type => '输入'; + + @override + String get chat_path => '路径'; + + @override + String get chat_publicKey => '公钥'; + + @override + String get chat_compressOutgoingMessages => '压缩发送的消息'; + + @override + String get chat_floodForced => '强制溢出'; + + @override + String get chat_directForced => '强制直接'; + + @override + String chat_hopsForced(int count) { + return '$count 次跳跃 (强制)'; + } + + @override + String get chat_floodAuto => '自动防洪'; + + @override + String get chat_direct => '直接'; + + @override + String get chat_poiShared => '共享位置信息'; + + @override + String chat_unread(int count) { + return '未读:$count'; + } + + @override + String get map_title => '节点地图'; + + @override + String get map_noNodesWithLocation => '没有具有位置数据的节点'; + + @override + String get map_nodesNeedGps => '节点需要共享它们的 GPS 坐标\n才能在地图上显示'; + + @override + String map_nodesCount(int count) { + return '节点:$count'; + } + + @override + String map_pinsCount(int count) { + return '针:$count'; + } + + @override + String get map_chat => '聊天'; + + @override + String get map_repeater => '重复器'; + + @override + String get map_room => '房间'; + + @override + String get map_sensor => '传感器'; + + @override + String get map_pinDm => '私信 (DM)'; + + @override + String get map_pinPrivate => '私密模式'; + + @override + String get map_pinPublic => '公开(公版)'; + + @override + String get map_lastSeen => '最后一次登录'; + + @override + String get map_disconnectConfirm => '您确定要断开与此设备的连接吗?'; + + @override + String get map_from => '从'; + + @override + String get map_source => '来源'; + + @override + String get map_flags => '旗帜'; + + @override + String get map_shareMarkerHere => '分享标记在此'; + + @override + String get map_pinLabel => '固定标签'; + + @override + String get map_label => '标签'; + + @override + String get map_pointOfInterest => '兴趣点'; + + @override + String get map_sendToContact => '发送给联系人'; + + @override + String get map_sendToChannel => '发送到频道'; + + @override + String get map_noChannelsAvailable => '没有可用的频道'; + + @override + String get map_publicLocationShare => '公共位置共享'; + + @override + String map_publicLocationShareConfirm(String channelLabel) { + return '您即将分享一个位置在 $channelLabel。此频道公开,任何拥有 PSK 的人都可以看到它。'; + } + + @override + String get map_connectToShareMarkers => '连接设备以共享标记'; + + @override + String get map_filterNodes => '筛选节点'; + + @override + String get map_nodeTypes => '节点类型'; + + @override + String get map_chatNodes => '聊天节点'; + + @override + String get map_repeaters => '重复器'; + + @override + String get map_otherNodes => '其他节点'; + + @override + String get map_keyPrefix => '键前缀'; + + @override + String get map_filterByKeyPrefix => '按关键词前缀筛选'; + + @override + String get map_publicKeyPrefix => '公钥前缀'; + + @override + String get map_markers => '标记'; + + @override + String get map_showSharedMarkers => '显示共享标记'; + + @override + String get map_lastSeenTime => '最后一次查看时间'; + + @override + String get map_sharedPin => '共享 PIN'; + + @override + String get map_joinRoom => '加入房间'; + + @override + String get map_manageRepeater => '管理重复项'; + + @override + String get mapCache_title => '离线地图缓存'; + + @override + String get mapCache_selectAreaFirst => '选择一个区域进行缓存'; + + @override + String get mapCache_noTilesToDownload => '该区域没有可下载的瓦片。'; + + @override + String get mapCache_downloadTilesTitle => '下载瓦片'; + + @override + String mapCache_downloadTilesPrompt(int count) { + return '下载 $count 个瓦片用于离线使用?'; + } + + @override + String get mapCache_downloadAction => '下载'; + + @override + String mapCache_cachedTiles(int count) { + return '已缓存 $count 个瓦片'; + } + + @override + String mapCache_cachedTilesWithFailed(int downloaded, int failed) { + return '已缓存 $downloaded 个瓦片 ($failed 失败)'; + } + + @override + String get mapCache_clearOfflineCacheTitle => '清除离线缓存'; + + @override + String get mapCache_clearOfflineCachePrompt => '删除所有缓存地图瓦片?'; + + @override + String get mapCache_offlineCacheCleared => '离线缓存已清除'; + + @override + String get mapCache_noAreaSelected => '未选择任何区域'; + + @override + String get mapCache_cacheArea => '缓存区域'; + + @override + String get mapCache_useCurrentView => '使用当前视图'; + + @override + String get mapCache_zoomRange => '缩放范围'; + + @override + String mapCache_estimatedTiles(int count) { + return '预计瓦片数量:$count'; + } + + @override + String mapCache_downloadedTiles(int completed, int total) { + return '已下载 $completed / $total'; + } + + @override + String get mapCache_downloadTilesButton => '下载瓦片'; + + @override + String get mapCache_clearCacheButton => '清除缓存'; + + @override + String mapCache_failedDownloads(int count) { + return '下载失败:$count'; + } + + @override + String mapCache_boundsLabel( + String north, + String south, + String east, + String west, + ) { + return '北 $north, 南 $south, 东 $east, 西 $west'; + } + + @override + String get time_justNow => '刚才'; + + @override + String time_minutesAgo(int minutes) { + return '$minutes分钟前'; + } + + @override + String time_hoursAgo(int hours) { + return '$hours小时前'; + } + + @override + String time_daysAgo(int days) { + return '$days 天前'; + } + + @override + String get time_hour => '小时'; + + @override + String get time_hours => '小时'; + + @override + String get time_day => '今天'; + + @override + String get time_days => '天'; + + @override + String get time_week => '本周'; + + @override + String get time_weeks => '几周'; + + @override + String get time_month => '月份'; + + @override + String get time_months => '月份'; + + @override + String get time_minutes => '分钟'; + + @override + String get time_allTime => '所有时间'; + + @override + String get dialog_disconnect => '断开'; + + @override + String get dialog_disconnectConfirm => '您确定要断开与此设备的连接吗?'; + + @override + String get login_repeaterLogin => '重复登录'; + + @override + String get login_roomLogin => '房间登录'; + + @override + String get login_password => '密码'; + + @override + String get login_enterPassword => '请输入密码'; + + @override + String get login_savePassword => '保存密码'; + + @override + String get login_savePasswordSubtitle => '密码将安全地存储在这个设备上'; + + @override + String get login_repeaterDescription => '输入重复密码以访问设置和状态。'; + + @override + String get login_roomDescription => '输入房间密码以访问设置和状态。'; + + @override + String get login_routing => '路由'; + + @override + String get login_routingMode => '路由模式'; + + @override + String get login_autoUseSavedPath => '自动(使用已保存路径)'; + + @override + String get login_forceFloodMode => '强制洪水模式'; + + @override + String get login_managePaths => '管理路径'; + + @override + String get login_login => '登录'; + + @override + String login_attempt(int current, int max) { + return '尝试 $current/$max'; + } + + @override + String login_failed(String error) { + return '登录失败:$error'; + } + + @override + String get common_reload => '重新加载'; + + @override + String get common_clear => '清除'; + + @override + String path_currentPath(String path) { + return '当前路径:$path'; + } + + @override + String path_usingHopsPath(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hops', + one: 'hop', + ); + return '使用 $count $_temp0 路径'; + } + + @override + String get path_enterCustomPath => '输入自定义路径'; + + @override + String get path_currentPathLabel => '当前路径'; + + @override + String get path_hexPrefixInstructions => '输入2个字符的十六进制前缀,每个前缀之间用逗号分隔。'; + + @override + String get path_hexPrefixExample => 'A1,F2,3C (每个节点使用其公钥的第一字节)'; + + @override + String get path_labelHexPrefixes => '十六进制前缀'; + + @override + String get path_helperMaxHops => '最大 64 步跳。每个前缀是 2 个十六进制字符(1 字节)'; + + @override + String get path_selectFromContacts => '或从联系人中选择:'; + + @override + String get path_noRepeatersFound => '未找到任何重复器或房间服务器。'; + + @override + String get path_customPathsRequire => '自定义路径需要中间跳转,这些跳转可以传递消息。'; + + @override + String path_invalidHexPrefixes(String prefixes) { + return '无效的十六进制前缀:$prefixes'; + } + + @override + String get path_tooLong => '路径太长。允许的最大跳跃次数为 64 次。'; + + @override + String get path_setPath => '设置路径'; + + @override + String get repeater_management => '重复器管理'; + + @override + String get repeater_managementTools => '管理工具'; + + @override + String get repeater_status => '状态'; + + @override + String get repeater_statusSubtitle => '查看重复器状态、统计信息和邻居'; + + @override + String get repeater_telemetry => '遥测'; + + @override + String get repeater_telemetrySubtitle => '查看传感器和系统状态的Telemetry数据'; + + @override + String get repeater_cli => 'CLI'; + + @override + String get repeater_cliSubtitle => '发送命令到重复器'; + + @override + String get repeater_settings => '设置'; + + @override + String get repeater_settingsSubtitle => '配置重复器参数'; + + @override + String get repeater_statusTitle => '重复器状态'; + + @override + String get repeater_routingMode => '路由模式'; + + @override + String get repeater_autoUseSavedPath => '自动(使用已保存路径)'; + + @override + String get repeater_forceFloodMode => '强制洪水模式'; + + @override + String get repeater_pathManagement => '路径管理'; + + @override + String get repeater_refresh => '刷新'; + + @override + String get repeater_statusRequestTimeout => '状态请求超时。'; + + @override + String repeater_errorLoadingStatus(String error) { + return '错误加载状态:$error'; + } + + @override + String get repeater_systemInformation => '系统信息'; + + @override + String get repeater_battery => '电池'; + + @override + String get repeater_clockAtLogin => '时间 (登录时)'; + + @override + String get repeater_uptime => '可用时间'; + + @override + String get repeater_queueLength => '排队长度'; + + @override + String get repeater_debugFlags => '调试标志'; + + @override + String get repeater_radioStatistics => '无线电统计'; + + @override + String get repeater_lastRssi => '上次RSSI'; + + @override + String get repeater_lastSnr => '最后 SNR'; + + @override + String get repeater_noiseFloor => '噪声地板'; + + @override + String get repeater_txAirtime => 'TX Airtime'; + + @override + String get repeater_rxAirtime => 'RX Airtime'; + + @override + String get repeater_packetStatistics => '数据包统计'; + + @override + String get repeater_sent => '已发送'; + + @override + String get repeater_received => '已收到'; + + @override + String get repeater_duplicates => '重复'; + + @override + String repeater_daysHoursMinsSecs( + int days, + int hours, + int minutes, + int seconds, + ) { + return '$days天 $hours小时 $minutes分 $seconds秒'; + } + + @override + String repeater_packetTxTotal(int total, String flood, String direct) { + return '总计:$total, 洪流:$flood, 直连:$direct'; + } + + @override + String repeater_packetRxTotal(int total, String flood, String direct) { + return '总计:$total, 洪流:$flood, 直连:$direct'; + } + + @override + String repeater_duplicatesFloodDirect(String flood, String direct) { + return '洪水:$flood, 直通:$direct'; + } + + @override + String repeater_duplicatesTotal(int total) { + return '总计:$total'; + } + + @override + String get repeater_settingsTitle => '重复设置'; + + @override + String get repeater_basicSettings => '基本设置'; + + @override + String get repeater_repeaterName => '重复器名称'; + + @override + String get repeater_repeaterNameHelper => '显示此重复器的名称'; + + @override + String get repeater_adminPassword => '管理员密码'; + + @override + String get repeater_adminPasswordHelper => '完整访问密码'; + + @override + String get repeater_guestPassword => '访客密码'; + + @override + String get repeater_guestPasswordHelper => '只读访问密码'; + + @override + String get repeater_radioSettings => '射频设置'; + + @override + String get repeater_frequencyMhz => '频率 (MHz)'; + + @override + String get repeater_frequencyHelper => '300-2500 MHz'; + + @override + String get repeater_txPower => 'TX Power'; + + @override + String get repeater_txPowerHelper => '1-30 dBm'; + + @override + String get repeater_bandwidth => '带宽'; + + @override + String get repeater_spreadingFactor => '扩散因子'; + + @override + String get repeater_codingRate => '编码速率'; + + @override + String get repeater_locationSettings => '位置设置'; + + @override + String get repeater_latitude => '纬度'; + + @override + String get repeater_latitudeHelper => '十进度的数字(例如:37.7749)'; + + @override + String get repeater_longitude => '经度'; + + @override + String get repeater_longitudeHelper => '十进度的数字(例如:-122.4194)'; + + @override + String get repeater_features => '功能'; + + @override + String get repeater_packetForwarding => '数据包转发'; + + @override + String get repeater_packetForwardingSubtitle => '启用重复器以转发数据包'; + + @override + String get repeater_guestAccess => '访客访问'; + + @override + String get repeater_guestAccessSubtitle => '允许访客仅读访问'; + + @override + String get repeater_privacyMode => '隐私模式'; + + @override + String get repeater_privacyModeSubtitle => '隐藏在广告中的姓名/位置'; + + @override + String get repeater_advertisementSettings => '广告设置'; + + @override + String get repeater_localAdvertInterval => '本地广告间隔'; + + @override + String repeater_localAdvertIntervalMinutes(int minutes) { + return '$minutes 分钟'; + } + + @override + String get repeater_floodAdvertInterval => '洪水广告间隔'; + + @override + String repeater_floodAdvertIntervalHours(int hours) { + return '$hours 小时'; + } + + @override + String get repeater_encryptedAdvertInterval => '加密广告间隔'; + + @override + String get repeater_dangerZone => '危险区域'; + + @override + String get repeater_rebootRepeater => '重启重复器'; + + @override + String get repeater_rebootRepeaterSubtitle => '重启重复器设备'; + + @override + String get repeater_rebootRepeaterConfirm => '您确定要重启这个中继器吗?'; + + @override + String get repeater_regenerateIdentityKey => '重新生成身份密钥'; + + @override + String get repeater_regenerateIdentityKeySubtitle => '生成新的公钥/私钥对'; + + @override + String get repeater_regenerateIdentityKeyConfirm => '这将生成一个重复器的新身份。继续吗?'; + + @override + String get repeater_eraseFileSystem => '删除文件系统'; + + @override + String get repeater_eraseFileSystemSubtitle => '格式化重复文件系统'; + + @override + String get repeater_eraseFileSystemConfirm => '警告:这将擦除重复器上的所有数据。 这无法撤销!'; + + @override + String get repeater_eraseSerialOnly => '通过串行控制台才能删除。'; + + @override + String repeater_commandSent(String command) { + return '命令已发送:$command'; + } + + @override + String repeater_errorSendingCommand(String error) { + return '发送命令时出错:$error'; + } + + @override + String get repeater_confirm => '确认'; + + @override + String get repeater_settingsSaved => '设置已保存成功'; + + @override + String repeater_errorSavingSettings(String error) { + return '保存设置出错:$error'; + } + + @override + String get repeater_refreshBasicSettings => '刷新基本设置'; + + @override + String get repeater_refreshRadioSettings => '刷新无线电设置'; + + @override + String get repeater_refreshTxPower => '刷新 TX 电量'; + + @override + String get repeater_refreshLocationSettings => '刷新位置设置'; + + @override + String get repeater_refreshPacketForwarding => '刷新包转发'; + + @override + String get repeater_refreshGuestAccess => '刷新访客访问'; + + @override + String get repeater_refreshPrivacyMode => '刷新隐私模式'; + + @override + String get repeater_refreshAdvertisementSettings => '刷新广告设置'; + + @override + String repeater_refreshed(String label) { + return '$label 已刷新'; + } + + @override + String repeater_errorRefreshing(String label) { + return '刷新 $label 时出错'; + } + + @override + String get repeater_cliTitle => '重复器命令行工具'; + + @override + String get repeater_debugNextCommand => '调试下一步命令'; + + @override + String get repeater_commandHelp => '帮助'; + + @override + String get repeater_clearHistory => '清除历史'; + + @override + String get repeater_noCommandsSent => '尚未发送任何命令'; + + @override + String get repeater_typeCommandOrUseQuick => '输入命令或使用快捷命令'; + + @override + String get repeater_enterCommandHint => '输入命令...'; + + @override + String get repeater_previousCommand => '上一个命令'; + + @override + String get repeater_nextCommand => '下一步命令'; + + @override + String get repeater_enterCommandFirst => '请输入一个命令'; + + @override + String get repeater_cliCommandFrameTitle => 'CLI 命令窗口'; + + @override + String repeater_cliCommandError(String error) { + return '错误:$error'; + } + + @override + String get repeater_cliQuickGetName => '获取姓名'; + + @override + String get repeater_cliQuickGetRadio => '获取收音机'; + + @override + String get repeater_cliQuickGetTx => '获取 TX'; + + @override + String get repeater_cliQuickNeighbors => '邻居'; + + @override + String get repeater_cliQuickVersion => '版本'; + + @override + String get repeater_cliQuickAdvertise => '发布'; + + @override + String get repeater_cliQuickClock => '时钟'; + + @override + String get repeater_cliHelpAdvert => '发送广告包'; + + @override + String get repeater_cliHelpReboot => '重启设备。(请注意,可能会出现“超时”现象,这是正常现象)'; + + @override + String get repeater_cliHelpClock => '显示每个设备的当前时间。'; + + @override + String get repeater_cliHelpPassword => '设置设备的新管理员密码。'; + + @override + String get repeater_cliHelpVersion => '显示设备版本和固件构建日期。'; + + @override + String get repeater_cliHelpClearStats => '重置各种统计数值为零。'; + + @override + String get repeater_cliHelpSetAf => '设置空闲时间因子。'; + + @override + String get repeater_cliHelpSetTx => '设置 LoRa 传输功率 (重置生效)'; + + @override + String get repeater_cliHelpSetRepeat => '启用或禁用此节点的重复器角色。'; + + @override + String get repeater_cliHelpSetAllowReadOnly => + '(房间服务器) 如果“开”了,则空密码登录将被允许,但不能向房间发布内容。(仅限读取)'; + + @override + String get repeater_cliHelpSetFloodMax => '设置最大换路包数量(如果 >= 最大,则不转发包)。'; + + @override + String get repeater_cliHelpSetIntThresh => + '设置干扰阈值(以 dB 为单位)。默认值为 14。将设置为 0 以禁用通道干扰检测。'; + + @override + String get repeater_cliHelpSetAgcResetInterval => + '设置间隔以重置自动增益控制器。将设置为 0 以禁用。'; + + @override + String get repeater_cliHelpSetMultiAcks => '启用或禁用“双 ACKs”功能。'; + + @override + String get repeater_cliHelpSetAdvertInterval => + '设置定时器间隔时间为分钟,以发送本地(零跳)广告包。将设置为0以禁用。'; + + @override + String get repeater_cliHelpSetFloodAdvertInterval => + '设置定时器间隔时间为小时,以发送洪水广告包。将设置为 0 以禁用。'; + + @override + String get repeater_cliHelpSetGuestPassword => + '设置/更新客人密码。(对于重复器,客人在登录时可以发送“获取统计”请求)'; + + @override + String get repeater_cliHelpSetName => '设置广告名称。'; + + @override + String get repeater_cliHelpSetLat => '设置广告地图纬度(十进制度)'; + + @override + String get repeater_cliHelpSetLon => '设置广告地图经度 (十进位)'; + + @override + String get repeater_cliHelpSetRadio => '设置全新的无线电参数,并保存到偏好设置。需要执行“重启”命令才能应用。'; + + @override + String get repeater_cliHelpSetRxDelay => + '设置(实验性)的基础(必须大于 1 才能生效)是用于对接收到的数据包应用轻微延迟,基于信号强度/得分。将设置为 0 以禁用。'; + + @override + String get repeater_cliHelpSetTxDelay => + '设置一个与时间-在空气中(time-on-air)的系数,用于洪水模式的数据包,并结合随机插槽系统,以延迟其转发。(以降低碰撞的可能性)'; + + @override + String get repeater_cliHelpSetDirectTxDelay => + '与txdelay相同,但用于为直接模式包的转发应用随机延迟。'; + + @override + String get repeater_cliHelpSetBridgeEnabled => '启用/禁用桥梁'; + + @override + String get repeater_cliHelpSetBridgeDelay => '设置在重新发送数据包之前延迟时间。'; + + @override + String get repeater_cliHelpSetBridgeSource => '选择桥梁是否会重传接收到的数据包或发送的数据包。'; + + @override + String get repeater_cliHelpSetBridgeBaud => '设置rs232桥接的串口链路波特率。'; + + @override + String get repeater_cliHelpSetBridgeSecret => '设置 espnow 桥的秘密。'; + + @override + String get repeater_cliHelpSetAdcMultiplier => '设置自定义因子以调整报告的电池电压(仅限部分板卡支持)。'; + + @override + String get repeater_cliHelpTempRadio => + '设置临时无线电参数,持续指定的分钟数,之后恢复为原始无线电参数。(不保存到偏好设置)。'; + + @override + String get repeater_cliHelpSetPerm => + '修改ACL。如果“权限”为零,则删除匹配的条目(通过pubkey前缀)。如果pubkey-hex的完整长度且当前不在ACL中,则添加新条目。通过匹配pubkey前缀更新条目。权限位因固件角色而异,但低2位为:0(Guest)、1(只读)、2(读写)、3(Admin)'; + + @override + String get repeater_cliHelpGetBridgeType => '获取桥接类型:无,RS232,ESPNow'; + + @override + String get repeater_cliHelpLogStart => '开始将数据包记录到文件系统。'; + + @override + String get repeater_cliHelpLogStop => '停止将数据包记录到文件系统。'; + + @override + String get repeater_cliHelpLogErase => '删除文件系统中的包日志。'; + + @override + String get repeater_cliHelpNeighbors => + '显示通过零跳广告收听的其他重复节点列表。 每行是 id-prefix-hex:时间戳:snr-times-4'; + + @override + String get repeater_cliHelpNeighborRemove => + '移除邻居列表中第一个匹配的条目(通过十六进制 pubkey 前缀)。'; + + @override + String get repeater_cliHelpRegion => '(仅显示区域) 列出所有已定义的区域和当前的防洪权限。'; + + @override + String get repeater_cliHelpRegionLoad => + '注意:这是一个特殊的多命令调用。 随后的每个命令都是一个区域名称(用空格缩进以指示父级层次结构,至少需要一个空格)。 以发送一个空行/命令结束。'; + + @override + String get repeater_cliHelpRegionGet => + '搜索具有给定名称前缀的区域(或“”用于全局范围)。回复为“-> region-name (parent-name) ‘F’”'; + + @override + String get repeater_cliHelpRegionPut => '添加或更新区域定义,使用指定名称。'; + + @override + String get repeater_cliHelpRegionRemove => '删除指定名称的区域定义。(必须没有子区域)'; + + @override + String get repeater_cliHelpRegionAllowf => '设置指定区域的“洪水”权限。(“”代表全局/遗留范围)'; + + @override + String get repeater_cliHelpRegionDenyf => + '移除指定区域的‘F’lood权限。 (注意:目前阶段不建议在此范围内使用,尤其是全局/旧版范围!!)'; + + @override + String get repeater_cliHelpRegionHome => '回复当前“主页”区域。 (注意尚未应用,保留用于未来)'; + + @override + String get repeater_cliHelpRegionHomeSet => '设置‘主页’区域。'; + + @override + String get repeater_cliHelpRegionSave => '保存区域列表/地图到存储。'; + + @override + String get repeater_cliHelpGps => + '显示GPS状态。当GPS关闭时,回复仅为“关闭”,如果已开启,则回复为“开启”、“状态”、“定位”和卫星数量。'; + + @override + String get repeater_cliHelpGpsOnOff => '切换 GPS 开启状态。'; + + @override + String get repeater_cliHelpGpsSync => '同步节点时间与 GPS 钟。'; + + @override + String get repeater_cliHelpGpsSetLoc => '设置节点位置至 GPS 坐标并保存偏好设置。'; + + @override + String get repeater_cliHelpGpsAdvert => + '提供节点广告配置位置:\n- none:不包含位置在广告中\n- share:分享 GPS 位置(来自 SensorManager)\n- prefs:在偏好设置中投放位置'; + + @override + String get repeater_cliHelpGpsAdvertSet => '设置广告位置配置。'; + + @override + String get repeater_commandsListTitle => '命令列表'; + + @override + String get repeater_commandsListNote => '注意:对于各种“设置...”命令,也存在“获取...”命令。'; + + @override + String get repeater_general => '通用'; + + @override + String get repeater_settingsCategory => '设置'; + + @override + String get repeater_bridge => '桥'; + + @override + String get repeater_logging => '记录'; + + @override + String get repeater_neighborsRepeaterOnly => '邻居(仅限重复器)'; + + @override + String get repeater_regionManagementRepeaterOnly => '区域管理(仅限重复器)'; + + @override + String get repeater_regionNote => '区域命令已推出,用于管理区域定义和权限。'; + + @override + String get repeater_gpsManagement => 'GPS管理'; + + @override + String get repeater_gpsNote => 'GPS 命令已引入用于管理与位置相关的主题。'; + + @override + String get telemetry_receivedData => '接收遥测数据'; + + @override + String get telemetry_requestTimeout => '遥测请求超时。'; + + @override + String telemetry_errorLoading(String error) { + return '错误加载遥测数据:$error'; + } + + @override + String get telemetry_noData => '没有可用的 telemetry 数据。'; + + @override + String telemetry_channelTitle(int channel) { + return '频道 $channel'; + } + + @override + String get telemetry_batteryLabel => '电池'; + + @override + String get telemetry_voltageLabel => '电压'; + + @override + String get telemetry_mcuTemperatureLabel => 'MCU 温度'; + + @override + String get telemetry_temperatureLabel => '温度'; + + @override + String get telemetry_currentLabel => '当前'; + + @override + String telemetry_batteryValue(int percent, String volts) { + return '$percent% / ${volts}V'; + } + + @override + String telemetry_voltageValue(String volts) { + return '${volts}V'; + } + + @override + String telemetry_currentValue(String amps) { + return '${amps}A'; + } + + @override + String telemetry_temperatureValue(String celsius, String fahrenheit) { + return '$celsius°C / $fahrenheit°F'; + } + + @override + String get channelPath_title => '数据包路径'; + + @override + String get channelPath_viewMap => '查看地图'; + + @override + String get channelPath_otherObservedPaths => '其他观察到的路径'; + + @override + String get channelPath_repeaterHops => '重复跳跃'; + + @override + String get channelPath_noHopDetails => '此包的详细信息未提供。'; + + @override + String get channelPath_messageDetails => '消息详情'; + + @override + String get channelPath_senderLabel => '发件人'; + + @override + String get channelPath_timeLabel => '时间'; + + @override + String get channelPath_repeatsLabel => '重复'; + + @override + String channelPath_pathLabel(int index) { + return '路径 $index'; + } + + @override + String get channelPath_observedLabel => '已观察'; + + @override + String channelPath_observedPathTitle(int index, String hops) { + return '观察路径 $index • $hops'; + } + + @override + String get channelPath_noLocationData => '没有位置数据'; + + @override + String channelPath_timeWithDate(int day, int month, String time) { + return '$day/$month $time'; + } + + @override + String channelPath_timeOnly(String time) { + return '$time'; + } + + @override + String get channelPath_unknownPath => '未知'; + + @override + String get channelPath_floodPath => '洪水'; + + @override + String get channelPath_directPath => '直接'; + + @override + String channelPath_observedZeroOf(int total) { + return '0 of $total 跳跃'; + } + + @override + String channelPath_observedSomeOf(int observed, int total) { + return '已观察到 $observed 步中的 $total 步'; + } + + @override + String get channelPath_mapTitle => '路径地图'; + + @override + String get channelPath_noRepeaterLocations => '此路径没有可用的重复器位置。'; + + @override + String channelPath_primaryPath(int index) { + return '路径 $index (主)'; + } + + @override + String get channelPath_pathLabelTitle => '路径'; + + @override + String get channelPath_observedPathHeader => '已观察路径'; + + @override + String channelPath_selectedPathLabel(String label, String prefixes) { + return '$label • $prefixes'; + } + + @override + String get channelPath_noHopDetailsAvailable => '此包的跳跃详情不可用。'; + + @override + String get channelPath_unknownRepeater => '未知重复器'; + + @override + String get listFilter_tooltip => '筛选和排序'; + + @override + String get listFilter_sortBy => '按类型排序'; + + @override + String get listFilter_latestMessages => '最新消息'; + + @override + String get listFilter_heardRecently => '最近听说'; + + @override + String get listFilter_az => 'A-Z'; + + @override + String get listFilter_filters => '筛选'; + + @override + String get listFilter_all => '全部'; + + @override + String get listFilter_users => '用户'; + + @override + String get listFilter_repeaters => '重复器'; + + @override + String get listFilter_roomServers => '房间服务器'; + + @override + String get listFilter_unreadOnly => '未读消息'; + + @override + String get listFilter_newGroup => '新组'; +} diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb new file mode 100644 index 0000000..da33f11 --- /dev/null +++ b/lib/l10n/app_nl.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "nl", + "appTitle": "MeshCore Open", + "nav_contacts": "Contacten", + "nav_channels": "Kanaal", + "nav_map": "Kaart", + "common_cancel": "Annuleren", + "common_connect": "Verbinden", + "common_unknownDevice": "Onbekend apparaat", + "common_save": "Opslaan", + "common_delete": "Verwijderen", + "common_close": "Sluiten", + "common_edit": "Bewerk", + "common_add": "Toevoegen", + "common_settings": "Instellingen", + "common_disconnect": "Verbinden verbreken", + "common_connected": "Verbonden", + "common_disconnected": "Ontkoppeld", + "common_create": "Maak", + "common_continue": "Doorgaan", + "common_share": "Delen", + "common_copy": "Kopiëren", + "common_retry": "Nogmaals proberen", + "common_hide": "Verbergen", + "common_remove": "Verwijderen", + "common_enable": "Aktivatie", + "common_disable": "Uitschakelen", + "common_reboot": "Herstarten", + "common_loading": "Laad...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Scannen naar apparaten...", + "scanner_connecting": "Verbinden...", + "scanner_disconnecting": "Verbinding verbreken...", + "scanner_notConnected": "Niet verbonden", + "scanner_connectedTo": "Verbonden met {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Zoeken naar MeshCore apparaten...", + "scanner_tapToScan": "Tik Scan om MeshCore apparaten te vinden", + "scanner_connectionFailed": "Verbinding mislukt: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Stoppen", + "scanner_scan": "Scan", + "device_quickSwitch": "Snelle overschakeling", + "device_meshcore": "MeshCore", + "settings_title": "Instellingen", + "settings_deviceInfo": "Apparateninformatie", + "settings_appSettings": "App Instellingen", + "settings_appSettingsSubtitle": "Notificaties, berichten en kaartinstellingen", + "settings_nodeSettings": "Node Instellingen", + "settings_nodeName": "Node Naam", + "settings_nodeNameNotSet": "Niet ingesteld", + "settings_nodeNameHint": "Voer knooppuntnaam in", + "settings_nodeNameUpdated": "Naam bijgewerkt", + "settings_radioSettings": "Radio Instellingen", + "settings_radioSettingsSubtitle": "Frequentie, vermogen, spredfactor", + "settings_radioSettingsUpdated": "Radio instellingen bijgewerkt", + "settings_location": "Locatie", + "settings_locationSubtitle": "GPS coördinaten", + "settings_locationUpdated": "Locatie bijgewerkt", + "settings_locationBothRequired": "Voer zowel breedte- als lengtegraad in.", + "settings_locationInvalid": "Ongeldige breedtegraad of lengtegraad.", + "settings_latitude": "Breedtegraad", + "settings_longitude": "Lengtegraad", + "settings_privacyMode": "Privacy Mode", + "settings_privacyModeSubtitle": "Naam/locatie verbergen in advertenties", + "settings_privacyModeToggle": "Schakel privacy modus in om je naam en locatie in advertenties te verbergen.", + "settings_privacyModeEnabled": "Privacy modus is ingeschakeld", + "settings_privacyModeDisabled": "Privacy modus is uitgeschakeld", + "settings_actions": "Acties", + "settings_sendAdvertisement": "Verzend Advertentie", + "settings_sendAdvertisementSubtitle": "Nu aanwezigheid uitzenden", + "settings_advertisementSent": "Advertentie verzonden", + "settings_syncTime": "Synchronisatie Tijd", + "settings_syncTimeSubtitle": "Stel de apparaatklok in op de tijd van de telefoon.", + "settings_timeSynchronized": "Tijdsynchronisatie", + "settings_refreshContacts": "Contacten vernieuwen", + "settings_refreshContactsSubtitle": "Contactlijst opnieuw laden van het apparaat", + "settings_rebootDevice": "Apparaat opnieuw opstarten", + "settings_rebootDeviceSubtitle": "Herstart het MeshCore apparaat", + "settings_rebootDeviceConfirm": "Ben je er zeker van dat je het apparaat opnieuw wilt opstarten? Je wordt losgekoppeld.", + "settings_debug": "Debug", + "settings_bleDebugLog": "BLE Debug Log", + "settings_bleDebugLogSubtitle": "BLE commando's, antwoorden en ruwe data", + "settings_appDebugLog": "App Debug Log", + "settings_appDebugLogSubtitle": "Toepassingsdebugberichten", + "settings_about": "Over", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "MeshCore Open Source Project 2024", + "settings_aboutDescription": "Een open-source Flutter client voor MeshCore LoRa mesh netwerkapparaten.", + "settings_infoName": "Naam", + "settings_infoId": "ID", + "settings_infoStatus": "Status", + "settings_infoBattery": "Batterij", + "settings_infoPublicKey": "Openbare Sleutel", + "settings_infoContactsCount": "Aantal Contacten", + "settings_infoChannelCount": "Kanaal Aantal", + "settings_presets": "Presets", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Frequentie (MHz)", + "settings_frequencyHelper": "300,0 - 2500,0", + "settings_frequencyInvalid": "Ongeldige frequentie (300-2500 MHz)", + "settings_bandwidth": "Bandbreedte", + "settings_spreadingFactor": "Spreadsnelheid", + "settings_codingRate": "Codeertarief", + "settings_txPower": "TX Vermogen (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Ongeldige TX-vermogen (0-22 dBm)", + "settings_longRange": "Lang Bereik", + "settings_fastSpeed": "Snelle Snelheid", + "settings_error": "Fout: {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "App Instellingen", + "appSettings_appearance": "Uiterlijk", + "appSettings_theme": "Thema", + "appSettings_themeSystem": "Standaardinstelling", + "appSettings_themeLight": "Helder", + "appSettings_themeDark": "Donker", + "appSettings_language": "Taal", + "appSettings_languageSystem": "Standaardinstelling", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Notificaties", + "appSettings_enableNotifications": "Notificaties inschakelen", + "appSettings_enableNotificationsSubtitle": "Ontvang meldingen voor berichten en advertenties", + "appSettings_notificationPermissionDenied": "Toestemming tot notificaties geweigerd", + "appSettings_notificationsEnabled": "Notificaties zijn ingeschakeld", + "appSettings_notificationsDisabled": "Notificaties zijn uitgeschakeld", + "appSettings_messageNotifications": "Berichtnotificaties", + "appSettings_messageNotificationsSubtitle": "Toon notificatie bij het ontvangen van nieuwe berichten", + "appSettings_channelMessageNotifications": "Kanaal Bericht Meldingen", + "appSettings_channelMessageNotificationsSubtitle": "Toon notificatie bij het ontvangen van kanaalberichten", + "appSettings_advertisementNotifications": "Advertentie-meldingen", + "appSettings_advertisementNotificationsSubtitle": "Toon notificatie wanneer nieuwe knooppunten worden ontdekt", + "appSettings_messaging": "Berichten", + "appSettings_clearPathOnMaxRetry": "Duidelijke Pad op Max Retry", + "appSettings_clearPathOnMaxRetrySubtitle": "Reset contactpad na 5 mislukte verzendpogingen", + "appSettings_pathsWillBeCleared": "De paden worden na 5 mislukte pogingen leeggehaald.", + "appSettings_pathsWillNotBeCleared": "Padoms worden niet automatisch verwijderd", + "appSettings_autoRouteRotation": "Automatische Route Rotatie", + "appSettings_autoRouteRotationSubtitle": "Wissel tussen de beste paden en floodmodus over.", + "appSettings_autoRouteRotationEnabled": "Automatische routeplanning rotatie ingeschakeld", + "appSettings_autoRouteRotationDisabled": "Automatische routeplanning rotatie is uitgeschakeld", + "appSettings_battery": "Batterij", + "appSettings_batteryChemistry": "Batterijchemie", + "appSettings_batteryChemistryPerDevice": "Instellen per apparaat ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Verbind met een apparaat om te selecteren", + "appSettings_batteryNmc": "18650 NMC (3,0-4,2V)", + "appSettings_batteryLifepo4": "LiFePO4 (2,6-3,65V)", + "appSettings_batteryLipo": "LiPo (3,0-4,2V)", + "appSettings_mapDisplay": "Kaartweergave", + "appSettings_showRepeaters": "Toon Herhalingen", + "appSettings_showRepeatersSubtitle": "Toon herhalende knoopjes op de kaart", + "appSettings_showChatNodes": "Chat Nodes tonen", + "appSettings_showChatNodesSubtitle": "Chatnodes weergeven op de kaart", + "appSettings_showOtherNodes": "Toon Andere Knopen", + "appSettings_showOtherNodesSubtitle": "Toon andere knooptypes op de kaart", + "appSettings_timeFilter": "Filter op tijd", + "appSettings_timeFilterShowAll": "Alle knooppunten tonen", + "appSettings_timeFilterShowLast": "Toon knopen van de laatste {hours} uur", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Filter tijd op kaart", + "appSettings_showNodesDiscoveredWithin": "Toon knooppunten ontdekt binnen:", + "appSettings_allTime": "Alle tijd", + "appSettings_lastHour": "Laat uur", + "appSettings_last6Hours": "laatste 6 uur", + "appSettings_last24Hours": "De laatste 24 uur", + "appSettings_lastWeek": "Laatste week", + "appSettings_offlineMapCache": "Offline Kaarten Cache", + "appSettings_noAreaSelected": "Geen gebied geselecteerd", + "appSettings_areaSelectedZoom": "Geselecteerd gebied (zoom {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Debug", + "appSettings_appDebugLogging": "App Debuggen Loggen", + "appSettings_appDebugLoggingSubtitle": "Log app debugberichten voor probleemoplossing", + "appSettings_appDebugLoggingEnabled": "App debug logging is ingeschakeld", + "appSettings_appDebugLoggingDisabled": "App debug logging is uitgeschakeld", + "contacts_title": "Contacten", + "contacts_noContacts": "Nog geen contacten.", + "contacts_contactsWillAppear": "Contacten verschijnen wanneer apparaten zich aanbieden.", + "contacts_searchContacts": "Zoek contacten...", + "contacts_noUnreadContacts": "Geen ongelezen contacten", + "contacts_noContactsFound": "Geen contacten of groepen gevonden.", + "contacts_deleteContact": "Verwijder Contact", + "contacts_removeConfirm": "Verwijder {contactName} uit de contacten?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Beheer Herhaling", + "contacts_roomLogin": "Ruimte Inloggen", + "contacts_openChat": "Open Chat", + "contacts_editGroup": "Groep bewerken", + "contacts_deleteGroup": "Groep verwijderen", + "contacts_deleteGroupConfirm": "Verwijder {groupName}?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Nieuwe Groep", + "contacts_groupName": "Groepnaam", + "contacts_groupNameRequired": "De groepnaam is verplicht.", + "contacts_groupAlreadyExists": "De groep \"{name}\" bestaat al.", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Filters contacten...", + "contacts_noContactsMatchFilter": "Geen contacten matchen met uw filter", + "contacts_noMembers": "Geen leden", + "contacts_lastSeenNow": "Laatste keer gezien nu", + "contacts_lastSeenMinsAgo": "Laast gezien {minutes} minuten geleden", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Laast gezien 1 uur geleden", + "contacts_lastSeenHoursAgo": "Laast gezien {hours} uur geleden", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Laatste bekeken 1 dag geleden", + "contacts_lastSeenDaysAgo": "Laast gezien {days} dagen geleden", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Kanaal", + "channels_noChannelsConfigured": "Geen kanalen geconfigureerd", + "channels_addPublicChannel": "Maak Open Kanaal", + "channels_searchChannels": "Zoek kanalen...", + "channels_noChannelsFound": "Geen kanalen gevonden", + "channels_channelIndex": "Kanaal {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Hashtag kanaal", + "channels_public": "Openbaar", + "channels_private": "Privé", + "channels_publicChannel": "Open kanaal", + "channels_privateChannel": "Private kanaal", + "channels_editChannel": "Kanaal bewerken", + "channels_deleteChannel": "Kanaal verwijderen", + "channels_deleteChannelConfirm": "Verwijderen \"{name}\"? Dit kan niet worden teruggedraaid.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Kanaal \"{name}\" verwijderd", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Kanaal toevoegen", + "channels_channelIndexLabel": "Kanaalindex", + "channels_channelName": "Kanaalnaam", + "channels_usePublicChannel": "Gebruik Open Kanaal", + "channels_standardPublicPsk": "Standaard open PSK", + "channels_pskHex": "PSK (Hex)", + "channels_generateRandomPsk": "Willekeurige PSK genereren", + "channels_enterChannelName": "Voer een kanaalnaam in", + "channels_pskMustBe32Hex": "De PSK moet 32 hexadecimale tekens zijn.", + "channels_channelAdded": "Kanaal \"{name}\" toegevoegd", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Bewerk Kanaal {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "SMAZ compressie", + "channels_channelUpdated": "Kanaal \"{name}\" is bijgewerkt", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "Open kanaal toegevoegd", + "channels_sortBy": "Sorteren door", + "channels_sortManual": "Handmatig", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "Recent berichten", + "channels_sortUnread": "Ongelezen", + "chat_noMessages": "Nog geen berichten.", + "chat_sendMessageToStart": "Een bericht sturen om te beginnen", + "chat_originalMessageNotFound": "Originele bericht niet gevonden", + "chat_replyingTo": "Reageren op {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Reageer op {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Locatie", + "chat_sendMessageTo": "Verstuur een bericht naar {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Type een bericht...", + "chat_messageTooLong": "Bericht is te lang (max {maxBytes} bytes).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Bericht gekopieerd", + "chat_messageDeleted": "Bericht verwijderd", + "chat_retryingMessage": "Poging opnieuw.", + "chat_retryCount": "Poging opnieuw {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "GIF verzenden", + "chat_reply": "Reageren", + "chat_addReaction": "Reactie toevoegen", + "chat_me": "Mijn", + "emojiCategorySmileys": "Emoji's", + "emojiCategoryGestures": "Bewegingen", + "emojiCategoryHearts": "Hartens", + "emojiCategoryObjects": "Objecten", + "gifPicker_title": "Kies een GIF", + "gifPicker_searchHint": "Zoek GIFs...", + "gifPicker_poweredBy": "Aangedreven door GIPHY", + "gifPicker_noGifsFound": "Geen GIFs gevonden", + "gifPicker_failedLoad": "GIF's konden niet worden geladen", + "gifPicker_failedSearch": "Zoeken mislukt", + "gifPicker_noInternet": "Geen internetverbinding", + "debugLog_appTitle": "App Debug Log", + "debugLog_bleTitle": "BLE Debug Log", + "debugLog_copyLog": "Kopieer log", + "debugLog_clearLog": "Log wissen", + "debugLog_copied": "Debuglog gekopieerd", + "debugLog_bleCopied": "BLE log gekopieerd", + "debugLog_noEntries": "Nog geen debug logs beschikbaar.", + "debugLog_enableInSettings": "Schakel app debug logging in de instellingen", + "debugLog_frames": "Ramen", + "debugLog_rawLogRx": "Raw Log-RX", + "debugLog_noBleActivity": "Geen BLE-activiteit nog.", + "debugFrame_length": "Frame Lengte: {count} bytes", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Boodschap: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Bericht Frame:", + "debugFrame_destinationPubKey": "- Bestemming PubKey: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Tijdstempel: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Vlaggen: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- Tekstdocumenttype: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Eenvoudig", + "debugFrame_text": "- Tekst: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Hex Dump:", + "chat_pathManagement": "Beheer van Paden", + "chat_routingMode": "Routeerwijze", + "chat_autoUseSavedPath": "Automatisch (gebruik opgeslagen pad)", + "chat_forceFloodMode": "Dwing Overstromingsmodus", + "chat_recentAckPaths": "Recente ACK Paden (tik om te gebruiken):", + "chat_pathHistoryFull": "De voorgeschiedenis is vol. Verwijder vermeldingen om er nieuwe aan toe te voegen.", + "chat_hopSingular": "Hop", + "chat_hopPlural": "hoppen", + "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "Succesvol", + "chat_removePath": "Pad verwijderen", + "chat_noPathHistoryYet": "Geen geschiedenis van paden nog beschikbaar.\nVerzend een bericht om paden te ontdekken.", + "chat_pathActions": "Padacties:", + "chat_setCustomPath": "Stel aangepaste pad in", + "chat_setCustomPathSubtitle": "Handmatig routepad specificeren", + "chat_clearPath": "Duidelijke Pad", + "chat_clearPathSubtitle": "Dwing herontdekking bij volgende verzending", + "chat_pathCleared": "Pad is vrijgegeven. Volgende bericht herontdekt route.", + "chat_floodModeSubtitle": "Gebruik de route-schakelaar in de app-balk", + "chat_floodModeEnabled": "Overstromingsmodus is ingeschakeld. Schakel dit uit via het route-icoon in de app-balk.", + "chat_fullPath": "Volledige Pad", + "chat_pathDetailsNotAvailable": "De paddetails zijn nog niet beschikbaar. Probeer een bericht te sturen om te vernieuwen.", + "chat_pathSetHops": "Pad ingesteld: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Opgeslagen lokaal. Verbinden om te synchroniseren.", + "chat_pathDeviceConfirmed": "Apparaat bevestigd.", + "chat_pathDeviceNotConfirmed": "Apparaat nog niet bevestigd.", + "chat_type": "Typen", + "chat_path": "Pad", + "chat_publicKey": "Openbare Sleutel", + "chat_compressOutgoingMessages": "Verzenden van uitgaande berichten comprimeren", + "chat_floodForced": "Overstroming (gedwongen)", + "chat_directForced": "Direct (gedwongen)", + "chat_hopsForced": "{count} sprongen (gedwongen)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Overstroming (auto)", + "chat_direct": "Direct", + "chat_poiShared": "Gedeelde POI", + "chat_unread": "Nieuw: {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Node Map", + "map_noNodesWithLocation": "Geen knopen met locatiegegevens", + "map_nodesNeedGps": "Nodes moeten hun GPS-coördinaten delen\nom op de kaart te verschijnen", + "map_nodesCount": "Nodes: {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Spelden: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Chat", + "map_repeater": "Herhaling", + "map_room": "Ruimte", + "map_sensor": "Sensor", + "map_pinDm": "Verzenden als bericht (DM)", + "map_pinPrivate": "Beveiligd (Privé)", + "map_pinPublic": "Openbaar spikken", + "map_lastSeen": "Laaste keer gezien", + "map_disconnectConfirm": "Ben je er zeker van dat je verbinding met dit apparaat wilt verbreken?", + "map_from": "Van", + "map_source": "Bron", + "map_flags": "Vlaggen", + "map_shareMarkerHere": "Deel marker hier", + "map_pinLabel": "Label vastzetten", + "map_label": "Label", + "map_pointOfInterest": "Interessepunt", + "map_sendToContact": "Verzenden naar contact", + "map_sendToChannel": "Verzenden naar kanaal", + "map_noChannelsAvailable": "Geen kanalen beschikbaar", + "map_publicLocationShare": "Openbare locatie delen", + "map_publicLocationShareConfirm": "U gaat een locatie delen in {channelLabel}. Deze kanaal is openbaar en iedereen met de PSK kan het zien.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Verbind met een apparaat om markers te delen", + "map_filterNodes": "Filter Knopen", + "map_nodeTypes": "Node Types", + "map_chatNodes": "Chat Nodes", + "map_repeaters": "Herhalingen", + "map_otherNodes": "Andere knooppunten", + "map_keyPrefix": "Prefix sleutel", + "map_filterByKeyPrefix": "Filteren op sleutelvoorgemeld", + "map_publicKeyPrefix": "Openbare sleutelvoorgemeld", + "map_markers": "Markeringen", + "map_showSharedMarkers": "Toon gedeelde markeringen", + "map_lastSeenTime": "Laatste Bekeken Tijd", + "map_sharedPin": "Gedeelde pin", + "map_joinRoom": "Sluit Kamer", + "map_manageRepeater": "Beheer Herhaling", + "mapCache_title": "Offline Kaarten Cache", + "mapCache_selectAreaFirst": "Select een gebied om eerst in de cache op te slaan", + "mapCache_noTilesToDownload": "Geen tiles te downloaden voor dit gebied.", + "mapCache_downloadTilesTitle": "Tiles downloaden", + "mapCache_downloadTilesPrompt": "Download {count} tegels voor offline gebruik?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Download", + "mapCache_cachedTiles": "Opgeslagen {count} tegels", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Opgeslagen {downloaded} tegels ({failed} mislukt)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Cache offline opschonen", + "mapCache_clearOfflineCachePrompt": "Alle gecachte kaarttiles verwijderen?", + "mapCache_offlineCacheCleared": "Offline cache is leeggezet", + "mapCache_noAreaSelected": "Geen gebied geselecteerd", + "mapCache_cacheArea": "Cache-gebied", + "mapCache_useCurrentView": "Gebruik Huidige Weergave", + "mapCache_zoomRange": "Zoom Bereik", + "mapCache_estimatedTiles": "Geschatte tegels: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Gedownload {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Tiles downloaden", + "mapCache_clearCacheButton": "Cache legen", + "mapCache_failedDownloads": "Mislukte downloads: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Net nu", + "time_minutesAgo": "{minutes} minuten geleden", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours} uur geleden", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} dagen geleden", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "uur", + "time_hours": "uren", + "time_day": "dag", + "time_days": "dagen", + "time_week": "week", + "time_weeks": "weken", + "time_month": "maand", + "time_months": "maanden", + "time_minutes": "minuten", + "time_allTime": "Alle tijd", + "dialog_disconnect": "Verbinden verbreken", + "dialog_disconnectConfirm": "Ben je er zeker van dat je verbinding met dit apparaat wilt verbreken?", + "login_repeaterLogin": "Herhaalders Inloggen", + "login_roomLogin": "Ruimte Inloggen", + "login_password": "Wachtwoord", + "login_enterPassword": "Wachtwoord invoeren", + "login_savePassword": "Wachtwoord opslaan", + "login_savePasswordSubtitle": "Het wachtwoord wordt veilig op dit apparaat opgeslagen.", + "login_repeaterDescription": "Voer het wachtwoord van de herhaling in om instellingen en status te openen.", + "login_roomDescription": "Voer het wachtwoord van de kamer in om toegang te krijgen tot instellingen en status.", + "login_routing": "Routing", + "login_routingMode": "Routeerwijze", + "login_autoUseSavedPath": "Automatisch (gebruik opgeslagen pad)", + "login_forceFloodMode": "Dwing Overstromingsmodus", + "login_managePaths": "Padbeheer", + "login_login": "Inloggen", + "login_attempt": "Poging {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Inloggen mislukt: {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Opnieuw laden", + "common_clear": "Schoonmaken", + "path_currentPath": "Huidige pad: {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Gebruik {count} {count, plural, =1{hop} other{hops}} pad", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Voer aangepaste pad in", + "path_currentPathLabel": "Huidige pad", + "path_hexPrefixInstructions": "Voer 2-letter hex-voorgiffen voor elke hop in, gescheiden door komma's.", + "path_hexPrefixExample": "Voorbeeld: A1,F2,3C (elke node gebruikt het eerste byte van zijn openbare sleutel)", + "path_labelHexPrefixes": "Pad (hex-voorkeursletters)", + "path_helperMaxHops": "Maximaal 64 sprongen. Elke prefix is 2 hexadecimale tekens (1 byte)", + "path_selectFromContacts": "Of select contacten:", + "path_noRepeatersFound": "Geen herhalingen of zaalservers gevonden.", + "path_customPathsRequire": "Aangepaste paden vereisen tussentse overstappen die berichten kunnen doorgeven.", + "path_invalidHexPrefixes": "Ongeldige hex-voorkeursletters: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "Pad is te lang. Maximaal 64 sprongen zijn toegestaan.", + "path_setPath": "Stel Pad in", + "repeater_management": "Beheer Herhalingen", + "repeater_managementTools": "Beheerinstrumenten", + "repeater_status": "Status", + "repeater_statusSubtitle": "Status, statistieken en buren bekijken", + "repeater_telemetry": "Telemetry", + "repeater_telemetrySubtitle": "Bekijk telemetrie van sensoren en systeemgegevens", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Verzend commando's naar de herhaaldere", + "repeater_settings": "Instellingen", + "repeater_settingsSubtitle": "Configureer repeaterparameters", + "repeater_statusTitle": "Status herhalen", + "repeater_routingMode": "Routeerwijze", + "repeater_autoUseSavedPath": "Automatisch (gebruik opgeslagen pad)", + "repeater_forceFloodMode": "Dwing Overloopmodus", + "repeater_pathManagement": "Beheer van paden", + "repeater_refresh": "Vernieuwen", + "repeater_statusRequestTimeout": "Statusverzoek is uitgevallen.", + "repeater_errorLoadingStatus": "Fout bij het laden van de status: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Systeem Informatie", + "repeater_battery": "Batterij", + "repeater_clockAtLogin": "Tijd (bij aanmelden)", + "repeater_uptime": "Beschikbaarheid", + "repeater_queueLength": "Wachttijd", + "repeater_debugFlags": "Debug Flags", + "repeater_radioStatistics": "Radio Statistieken", + "repeater_lastRssi": "Laatste RSSI", + "repeater_lastSnr": "Laatste SNR", + "repeater_noiseFloor": "Ruishoordniveau", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Pakket Statistieken", + "repeater_sent": "Verzonden", + "repeater_received": "Ontvangen", + "repeater_duplicates": "Dubbele", + "repeater_daysHoursMinsSecs": "{days} dagen {hours} uur {minutes} minuten {seconds} seconden", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Totaal: {total}, Overstroming: {flood}, Direct: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Totaal: {total}, Overstroming: {flood}, Direct: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Overstroming: {flood}, Direct: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Totaal: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Herstelinstellingen", + "repeater_basicSettings": "Basisinstellingen", + "repeater_repeaterName": "Herhaalnaam", + "repeater_repeaterNameHelper": "Weergave naam voor deze herhaling", + "repeater_adminPassword": "Admin wachtwoord", + "repeater_adminPasswordHelper": "Volledige toegangspaswoord", + "repeater_guestPassword": "Wachtwoord Gast", + "repeater_guestPasswordHelper": "Leesbeheer wachtwoord", + "repeater_radioSettings": "Radio Instellingen", + "repeater_frequencyMhz": "Frequentie (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Power", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Bandbreedte", + "repeater_spreadingFactor": "Spreadsnelheid", + "repeater_codingRate": "Codeertarief", + "repeater_locationSettings": "Locatie Instellingen", + "repeater_latitude": "Breedtegraad", + "repeater_latitudeHelper": "Graadseconden (bijv. 37.7749)", + "repeater_longitude": "Lengtegraad", + "repeater_longitudeHelper": "Graadseconden (bijv. -122.4194)", + "repeater_features": "Kenmerken", + "repeater_packetForwarding": "Pakketdoorstrooming", + "repeater_packetForwardingSubtitle": "Herstel activeren om pakketten door te sturen", + "repeater_guestAccess": "Toegang voor Gasten", + "repeater_guestAccessSubtitle": "Toegestane leesbeheer toegang voor gasten.", + "repeater_privacyMode": "Privacy Mode", + "repeater_privacyModeSubtitle": "Naam/locatie verbergen in advertenties", + "repeater_advertisementSettings": "Advertentie Instellingen", + "repeater_localAdvertInterval": "Lokale Advertentie Interval", + "repeater_localAdvertIntervalMinutes": "{minutes} minuten", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Advertentie Interval bij overstroming", + "repeater_floodAdvertIntervalHours": "{hours} uur", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Versleutelde Advertentie Interval", + "repeater_dangerZone": "Gevaarzone", + "repeater_rebootRepeater": "Herstart Herhaalder", + "repeater_rebootRepeaterSubtitle": "De herstart van het herhalerapparaat", + "repeater_rebootRepeaterConfirm": "Ben je er zeker van dat je deze repeater opnieuw wilt opstarten?", + "repeater_regenerateIdentityKey": "Identiteit sleutel opnieuw genereren", + "repeater_regenerateIdentityKeySubtitle": "Nieuwe publieke/private sleutelpaar genereren", + "repeater_regenerateIdentityKeyConfirm": "Dit genereert een nieuwe identiteit voor de herhaling. Doorgaan?", + "repeater_eraseFileSystem": "Verwijder Besturingssysteem", + "repeater_eraseFileSystemSubtitle": "Formateer het herhalende bestandsysteem", + "repeater_eraseFileSystemConfirm": "WAARSCHUWING: Dit zal alle gegevens op de herhaling wissen. Dit kan niet worden teruggedraaid!", + "repeater_eraseSerialOnly": "Verwijderen is alleen beschikbaar via de seriële console.", + "repeater_commandSent": "Commando verzonden: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Fout bij het verzenden van de opdracht: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "Bevestigen", + "repeater_settingsSaved": "Instellingen succesvol opgeslagen", + "repeater_errorSavingSettings": "Fout bij het opslaan van de instellingen: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Basisinstellingen vernieuwen", + "repeater_refreshRadioSettings": "Radiozenders Instellingen Bijwerken", + "repeater_refreshTxPower": "Nieuw laden TX-vermogen", + "repeater_refreshLocationSettings": "Instellingen Locatie Vernieuwen", + "repeater_refreshPacketForwarding": "Vernieuwen Pakket Doorversturing", + "repeater_refreshGuestAccess": "Toegang Gast Vernieuwen", + "repeater_refreshPrivacyMode": "Privacy Mode vernieuwen", + "repeater_refreshAdvertisementSettings": "Instellingen Advertentie Bijwerken", + "repeater_refreshed": "{label} is vernieuwd", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Fout bij het vernieuwen van {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Herhaling CLI", + "repeater_debugNextCommand": "Debug Volgende Commando", + "repeater_commandHelp": "Help", + "repeater_clearHistory": "Verwijder Geschiedenis", + "repeater_noCommandsSent": "Geen commando's verzonden nog.", + "repeater_typeCommandOrUseQuick": "Typ een opdracht hieronder of gebruik snelle commando's", + "repeater_enterCommandHint": "Voer bevel in...", + "repeater_previousCommand": "Vorige opdracht", + "repeater_nextCommand": "Volgende opdracht", + "repeater_enterCommandFirst": "Voer eerst een commando in", + "repeater_cliCommandFrameTitle": "CLI Commando Frame", + "repeater_cliCommandError": "Fout: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Haal Naam op", + "repeater_cliQuickGetRadio": "Radio ontvangen", + "repeater_cliQuickGetTx": "Krijg TX", + "repeater_cliQuickNeighbors": "Buren", + "repeater_cliQuickVersion": "Versie", + "repeater_cliQuickAdvertise": "Advertenties", + "repeater_cliQuickClock": "Tijd", + "repeater_cliHelpAdvert": "Verstuurt een advertentiepakket", + "repeater_cliHelpReboot": "Herstart het apparaat. (let op, je krijgt mogelijk een 'Timeout', wat normaal is)", + "repeater_cliHelpClock": "Toont de huidige tijd per apparaat's klok.", + "repeater_cliHelpPassword": "Stelt een nieuw beheerderswachtwoord in voor het apparaat.", + "repeater_cliHelpVersion": "Toont de apparaatversie en firmware-bouwdatum.", + "repeater_cliHelpClearStats": "Reset verschillende statistiek-tellers naar nul.", + "repeater_cliHelpSetAf": "Stelt de luchtvaartfactor in.", + "repeater_cliHelpSetTx": "Stelt LoRa zendvermogen in dBm. (om te wijzigen)", + "repeater_cliHelpSetRepeat": "Activeert of deactiveert de herhalerrol voor dit knoop.", + "repeater_cliHelpSetAllowReadOnly": "(Kamervisie) Als 'aan', dan wordt inloggen met een blanco wachtwoord toegestaan, maar kan niet naar de kamervisie Posten. (alleen lezen mogelijk).", + "repeater_cliHelpSetFloodMax": "Stelt het maximale aantal hops van een inkomend overlastpakket in (indien >= max, wordt het pakket niet doorgestuurd)", + "repeater_cliHelpSetIntThresh": "Stelt de Interferentiewaarde (in dB) in. Standaardwaarde is 14. Stel in op 0 om het detecteren van kanaalinterferentie uit te schakelen.", + "repeater_cliHelpSetAgcResetInterval": "Stelt het interval in om de Auto Gain Controller te resetten. Stel in op 0 om dit uit te schakelen.", + "repeater_cliHelpSetMultiAcks": "Activeert of deactiveert de functie 'dubbele ACKs'.", + "repeater_cliHelpSetAdvertInterval": "Stelt het timerinterval in minuten in om een lokale (zero-hop) advertentiepakket te versturen. Stel in op 0 om uit te schakelen.", + "repeater_cliHelpSetFloodAdvertInterval": "Stelt het timerinterval in uren in om een overstromingsadvertentiepakket te versturen. Stel in op 0 om dit uit te schakelen.", + "repeater_cliHelpSetGuestPassword": "Stelt/past de gastenwacht aan of wijzigt deze. (voor herstelcontacten kunnen gastelogins de \"Get Stats\" verzoek verzenden)", + "repeater_cliHelpSetName": "Stelt de advertentietitel in.", + "repeater_cliHelpSetLat": "Stelt de breedtegraad van de advertentiekaart in. (graadrijssysteem)", + "repeater_cliHelpSetLon": "Stelt de lengtegraad van de advertentiekaart in. (graadrijtjes)", + "repeater_cliHelpSetRadio": "Stelt volledig nieuwe radio parameters in en slaat deze op in de instellingen. Vereist een \"reboot\" commando om toe te passen.", + "repeater_cliHelpSetRxDelay": "Sets (experimenteel) basis (moet > 1 zijn voor effect) om een lichte vertraging toe te passen op ontvangen pakketten, gebaseerd op signaalsterkte/score. Stel op 0 om uit te schakelen.", + "repeater_cliHelpSetTxDelay": "Stelt een factor in werking die wordt vermenigvuldigd met de tijd op lucht voor een flood-mode pakket en met een willekeurig slot systeem, om de verzending ervan te vertragen (om de kans op botsingen te verminderen).", + "repeater_cliHelpSetDirectTxDelay": "Vergelijkbaar met txdelay, maar voor het toepassen van een willekeurige vertraging bij het doorsturen van pakketten in directe modus.", + "repeater_cliHelpSetBridgeEnabled": "Poort inschakelen/uitschakelen.", + "repeater_cliHelpSetBridgeDelay": "Verzend vertraging instellen voor pakketten.", + "repeater_cliHelpSetBridgeSource": "Kies of de brug ontvangen pakketten of verzonden pakketten opnieuw moet versturen.", + "repeater_cliHelpSetBridgeBaud": "Stel de seriële link baudrate in voor rs232 bruggen.", + "repeater_cliHelpSetBridgeSecret": "Stel bridge-geheim in voor espnow bridges.", + "repeater_cliHelpSetAdcMultiplier": "Stelt een aangepaste factor in om de gerapporteerde batterijspanning aan te passen (alleen ondersteund op selecte borden).", + "repeater_cliHelpTempRadio": "Stelt tijdelijke radio parameters in voor het opgegeven aantal minuten, en keert daarna terug naar de originele radio parameters. (wordt niet opgeslagen in de voorkeuren).", + "repeater_cliHelpSetPerm": "Wijzigt de ACL. Verwijder de overeenkomstige entry (door pubkey prefix) als \"permissions\" 0 is. Voeg een nieuwe entry toe als pubkey-hex volledig is en niet momenteel in de ACL staat. Update de entry door matching pubkey prefix. Toestemming bits variëren per firmware rol, maar de onderste 2 bits zijn: 0 (Gast), 1 (Alleen lezen), 2 (Lezen/schrijven), 3 (Admin)", + "repeater_cliHelpGetBridgeType": "Ontvang brugtype: geen, rs232, espnow", + "repeater_cliHelpLogStart": "Start pakketlogging naar het bestandssysteem.", + "repeater_cliHelpLogStop": "Stoppen met het loggen van pakketten naar het bestandssysteem.", + "repeater_cliHelpLogErase": "Verwijdert de pakketlogs uit het bestandssysteem.", + "repeater_cliHelpNeighbors": "Toont een lijst met andere repeater nodes die via nul-hop advertenties zijn gehoord. Elke regel is id-prefix-hex:timestamp:snr-times-4", + "repeater_cliHelpNeighborRemove": "Verwijdert de eerste overeenkomende vermelding (via pubkey prefix (hex)) uit de lijst van buren.", + "repeater_cliHelpRegion": "(reeks alleen) Lijst alle gedefinieerde regio's en huidige overstromingsrechten.", + "repeater_cliHelpRegionLoad": "LET OP: dit is een speciale multi-command aanroep. Elke volgende opdracht is een regiortaak (uitgelijnd met spaties om de ouderhiërarchie aan te duiden, met minimaal één spatie). Beëindigd door een lege regel/opdracht te sturen.", + "repeater_cliHelpRegionGet": "Zoekt naar regio met gegeven naam voorvoegsel (of \"\" voor de globale scope). Antwoordt met \"-> regio-naam (ouder-naam) 'F'\"", + "repeater_cliHelpRegionPut": "Voegt of wijzigt een regio-definitie met de gegeven naam.", + "repeater_cliHelpRegionRemove": "Verwijdert een regio-definitie met de gegeven naam. (moet exact overeenkomen en geen kindregio's hebben)", + "repeater_cliHelpRegionAllowf": "Stelt de 'F'lood-toestemming in voor de opgegeven regio. ('' voor de globale/oude scope)", + "repeater_cliHelpRegionDenyf": "Verwijdert de 'F'lood-toestemming voor de gegeven regio. (LET OP: op dit moment niet aanbevolen om dit op de globale/oude scope te gebruiken!!)", + "repeater_cliHelpRegionHome": "Antwoorden met de huidige 'thuis'-regio. (Op dit moment nergens toegepast, gereserveerd voor toekomstig gebruik)", + "repeater_cliHelpRegionHomeSet": "Stelt de 'thuis'-regio in.", + "repeater_cliHelpRegionSave": "Bewaar de lijst/kaart van de regio's naar de opslag.", + "repeater_cliHelpGps": "Geeft de status van de GPS. Wanneer de GPS uit staat, antwoordt het alleen met \"uit\", als het aan staat, antwoordt het met \"aan\", status, fix, sat count.", + "repeater_cliHelpGpsOnOff": "Schakel de GPS-standby aan/uit.", + "repeater_cliHelpGpsSync": "Synchroniseer knooptime met GPS-klok.", + "repeater_cliHelpGpsSetLoc": "Stel de positie van het knoop vast naar GPS-coördinaten en sla de voorkeuren op.", + "repeater_cliHelpGpsAdvert": "Geeft de locatie advertentieconfiguratie van de node:\n- none: locatie niet in advertenties opnemen\n- share: gps locatie delen (van SensorManager)\n- prefs: locatie adverteren die in de voorkeuren is opgeslagen", + "repeater_cliHelpGpsAdvertSet": "Stelt advertentie locatie configuratie in.", + "repeater_commandsListTitle": "Commandenlijst", + "repeater_commandsListNote": "LET OP: voor de verschillende \"set ...\" commando's is er ook een \"get ...\" commando.", + "repeater_general": "Algemeen", + "repeater_settingsCategory": "Instellingen", + "repeater_bridge": "Bruggen", + "repeater_logging": "Logging", + "repeater_neighborsRepeaterOnly": "Buren (Alleen herhaald)", + "repeater_regionManagementRepeaterOnly": "Regiobeheer (Alleen voor Repeater)", + "repeater_regionNote": "Regio-commando's zijn geïntroduceerd om regio-definities en permissies te beheren.", + "repeater_gpsManagement": "Beheer GPS", + "repeater_gpsNote": "De GPS-commando is geïntroduceerd om locatiegerelateerde onderwerpen te beheren.", + "telemetry_receivedData": "Ontvangen Telemetriedata", + "telemetry_requestTimeout": "Telemetryverzoek is uitgevallen.", + "telemetry_errorLoading": "Fout bij het laden van de telemetrie: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "Geen telemetriedata beschikbaar.", + "telemetry_channelTitle": "Kanaal {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Batterij", + "telemetry_voltageLabel": "Spanning", + "telemetry_mcuTemperatureLabel": "MCU Temperatuur", + "telemetry_temperatureLabel": "Temperatuur", + "telemetry_currentLabel": "Huidig", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Pakketpad", + "channelPath_viewMap": "Kaart bekijken", + "channelPath_otherObservedPaths": "Overige Waargenomen Paden", + "channelPath_repeaterHops": "Herhalingstapjes", + "channelPath_noHopDetails": "De details van de pakket zijn niet verstrekt.", + "channelPath_messageDetails": "Details Bericht", + "channelPath_senderLabel": "Afzender", + "channelPath_timeLabel": "Tijd", + "channelPath_repeatsLabel": "Herhalen", + "channelPath_pathLabel": "Pad {index}", + "channelPath_observedLabel": "Waargenomen", + "channelPath_observedPathTitle": "Waargenomen pad {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "Geen locatiegegevens", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Onbekend", + "channelPath_floodPath": "Overstroming", + "channelPath_directPath": "Direct", + "channelPath_observedZeroOf": "0 van {total} sprongen", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} van {total} sprongen", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Padkaart", + "channelPath_noRepeaterLocations": "Geen herhaler locaties beschikbaar voor deze route.", + "channelPath_primaryPath": "Pad {index} (Hoofdtype)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Pad", + "channelPath_observedPathHeader": "Waargenomen Pad", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "Geen details beschikbaar voor dit pakket.", + "channelPath_unknownRepeater": "Onbekend Herhaalaar", + "listFilter_tooltip": "Filteren en sorteren", + "listFilter_sortBy": "Sorteren door", + "listFilter_latestMessages": "Recente berichten", + "listFilter_heardRecently": "Hoor je onlangs", + "listFilter_az": "A-Z", + "listFilter_filters": "Filters", + "listFilter_all": "Alles", + "listFilter_users": "Gebruikers", + "listFilter_repeaters": "Herhalingen", + "listFilter_roomServers": "Kamervirtualisatie", + "listFilter_unreadOnly": "Alleen ongelezen", + "listFilter_newGroup": "Nieuwe groep" +} diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb new file mode 100644 index 0000000..bab67b5 --- /dev/null +++ b/lib/l10n/app_pl.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "pl", + "appTitle": "MeshCore Open", + "nav_contacts": "Kontakty", + "nav_channels": "Kanały", + "nav_map": "Mapa", + "common_cancel": "Anuluj", + "common_connect": "Połącz", + "common_unknownDevice": "Nieznane urządzenie", + "common_save": "Zapisz", + "common_delete": "Usuń", + "common_close": "Zamknąć", + "common_edit": "Edytuj", + "common_add": "Dodaj", + "common_settings": "Ustawienia", + "common_disconnect": "Odłącz", + "common_connected": "Połączono", + "common_disconnected": "Odłączony", + "common_create": "Utwórz", + "common_continue": "Kontynuuj", + "common_share": "Udostępnij", + "common_copy": "Kopiuj", + "common_retry": "Spróbować", + "common_hide": "Ukryj", + "common_remove": "Usuń", + "common_enable": "Włącz", + "common_disable": "Wyłączyć", + "common_reboot": "Zrestartować", + "common_loading": "Ładowanie...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Skanowanie urządzeń...", + "scanner_connecting": "Łączenie...", + "scanner_disconnecting": "Odłączanie...", + "scanner_notConnected": "Niepołączony", + "scanner_connectedTo": "Połączono z {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Wyszukiwanie urządzeń MeshCore...", + "scanner_tapToScan": "Naciśnij Skan, aby znaleźć urządzenia MeshCore", + "scanner_connectionFailed": "Połączenie nieudane: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Zatrzymaj", + "scanner_scan": "Przeskanuj", + "device_quickSwitch": "Szybka zmiana", + "device_meshcore": "MeshCore", + "settings_title": "Ustawienia", + "settings_deviceInfo": "Informacje o urządzeniu", + "settings_appSettings": "Ustawienia aplikacji", + "settings_appSettingsSubtitle": "Powiadomienia, wiadomości i preferencje mapy", + "settings_nodeSettings": "Ustawienia węzła", + "settings_nodeName": "Nazwa węzła", + "settings_nodeNameNotSet": "Nie ustawione", + "settings_nodeNameHint": "Wprowadź nazwę węzła", + "settings_nodeNameUpdated": "Imię zaktualizowane", + "settings_radioSettings": "Ustawienia radia", + "settings_radioSettingsSubtitle": "Częstotliwość, moc, współczynnik rozpraszania", + "settings_radioSettingsUpdated": "Ustawienia radia zostały zaktualizowane", + "settings_location": "Lokalizacja", + "settings_locationSubtitle": "Koordynaty GPS", + "settings_locationUpdated": "Lokalizacja zaktualizowana", + "settings_locationBothRequired": "Wprowadź zarówno szerokość, jak i długość geograficzną.", + "settings_locationInvalid": "Nieprawidłowa szerokość geograficzna lub długość geograficzna.", + "settings_latitude": "Szerokość", + "settings_longitude": "Długość", + "settings_privacyMode": "Tryb Prywatny", + "settings_privacyModeSubtitle": "Ukryj imię/lokalizację w reklamach", + "settings_privacyModeToggle": "Włącz tryb prywatności, aby ukryć swoje imię i lokalizację w reklamach.", + "settings_privacyModeEnabled": "Tryb prywatności włączony", + "settings_privacyModeDisabled": "Tryb prywatności wyłączony", + "settings_actions": "Działania", + "settings_sendAdvertisement": "Wyślij Reklamę", + "settings_sendAdvertisementSubtitle": "Obecność transmisji jest teraz", + "settings_advertisementSent": "Reklama wysłana", + "settings_syncTime": "Czas synchronizacji", + "settings_syncTimeSubtitle": "Ustaw zegar urządzenia na czas telefonu.", + "settings_timeSynchronized": "Synchronizacja czasu", + "settings_refreshContacts": "Odśwież Kontakty", + "settings_refreshContactsSubtitle": "Odśwież listę kontaktów z urządzenia", + "settings_rebootDevice": "Zrestartuj Urządzenie", + "settings_rebootDeviceSubtitle": "Zrestartuj urządzenie MeshCore", + "settings_rebootDeviceConfirm": "Czy na pewno chcesz zrestartować urządzenie? Będziesz odłączony.", + "settings_debug": "Debug", + "settings_bleDebugLog": "Log błędów BLE", + "settings_bleDebugLogSubtitle": "Polecenia BLE, odpowiedzi i surowe dane", + "settings_appDebugLog": "Log Wykonywania Aplikacji", + "settings_appDebugLogSubtitle": "Komunikaty debugowania aplikacji", + "settings_about": "O mnie", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "Projekt MeshCore Open Source 2026", + "settings_aboutDescription": "Otwarty kod źródłowy klient Flutter dla urządzeń do sieci mesh LoRa MeshCore.", + "settings_infoName": "Imię", + "settings_infoId": "ID", + "settings_infoStatus": "Status", + "settings_infoBattery": "Bateria", + "settings_infoPublicKey": "Klucz Publiczny", + "settings_infoContactsCount": "Liczba kontaktów", + "settings_infoChannelCount": "Liczba kanałów", + "settings_presets": "Preset", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Częstotliwość (MHz)", + "settings_frequencyHelper": "300,0 - 2500,0", + "settings_frequencyInvalid": "Nieprawidłowa częstotliwość (300-2500 MHz)", + "settings_bandwidth": "Przepustowość", + "settings_spreadingFactor": "Rozkład Czynnika", + "settings_codingRate": "Stawka Kodowania", + "settings_txPower": "TX Moc (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Nieprawidłowa moc TX (0-22 dBm)", + "settings_longRange": "Długi zasięg", + "settings_fastSpeed": "Szybka prędkość", + "settings_error": "Błąd: {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "Ustawienia aplikacji", + "appSettings_appearance": "Wygląd", + "appSettings_theme": "Motyw", + "appSettings_themeSystem": "Domyślne ustawienia systemu", + "appSettings_themeLight": "Jasne", + "appSettings_themeDark": "Ciemny", + "appSettings_language": "Język", + "appSettings_languageSystem": "Domyślny systemowy", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Powiadomienia", + "appSettings_enableNotifications": "Włącz Powiadomienia", + "appSettings_enableNotificationsSubtitle": "Otrzymuj powiadomienia o wiadomościach i reklamach.", + "appSettings_notificationPermissionDenied": "Odmowa zezwolenia na powiadomienia", + "appSettings_notificationsEnabled": "Powiadomienia włączone", + "appSettings_notificationsDisabled": "Powiadomienia wyłączone", + "appSettings_messageNotifications": "Powiadomienia o wiadomościach", + "appSettings_messageNotificationsSubtitle": "Pokaż powiadomienie przy otrzymywaniu nowych wiadomości", + "appSettings_channelMessageNotifications": "Powiadomienia o Wiadomościach na Kanałach", + "appSettings_channelMessageNotificationsSubtitle": "Pokaż powiadomienie przy odbieraniu wiadomości z kanału", + "appSettings_advertisementNotifications": "Powiadomienia Reklamowe", + "appSettings_advertisementNotificationsSubtitle": "Wyświetl powiadomienie, gdy zostaną odkryte nowe węzły.", + "appSettings_messaging": "Wiadomości", + "appSettings_clearPathOnMaxRetry": "Wyczyść Ścieżkę na Maksymalnej Próbie", + "appSettings_clearPathOnMaxRetrySubtitle": "Resetuj ścieżkę kontaktu po 5 nieudanych próbach wysłania", + "appSettings_pathsWillBeCleared": "Droga będzie wyczyszczona po 5 nieudanych próbach.", + "appSettings_pathsWillNotBeCleared": "Droga nie zostanie automatycznie wyczyszczona.", + "appSettings_autoRouteRotation": "Automatyczne Rotowanie Trasy", + "appSettings_autoRouteRotationSubtitle": "Przełączaj się między najlepszymi ścieżkami a trybem zalewowym.", + "appSettings_autoRouteRotationEnabled": "Automatyczne obracanie tras włączone", + "appSettings_autoRouteRotationDisabled": "Automatyczne obracanie tras wyłączone", + "appSettings_battery": "Bateria", + "appSettings_batteryChemistry": "Chemia Baterii", + "appSettings_batteryChemistryPerDevice": "Ustawione na urządzenie ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Połącz się z urządzeniem, aby wybrać", + "appSettings_batteryNmc": "18650 NMC (3,0-4,2V)", + "appSettings_batteryLifepo4": "LiFePO4 (2,6-3,65 V)", + "appSettings_batteryLipo": "LiPo (3,0-4,2V)", + "appSettings_mapDisplay": "Wyświetlanie mapy", + "appSettings_showRepeaters": "Pokaż Powtórniki", + "appSettings_showRepeatersSubtitle": "Wyświetl węzły powtarzające się na mapie", + "appSettings_showChatNodes": "Pokaż Węzły Rozmowy", + "appSettings_showChatNodesSubtitle": "Wyświetl węzły czatu na mapie", + "appSettings_showOtherNodes": "Pokaż inne węzły", + "appSettings_showOtherNodesSubtitle": "Wyświetl inne typy węzłów na mapie", + "appSettings_timeFilter": "Filtrowanie Czasu", + "appSettings_timeFilterShowAll": "Pokaż wszystkie węzły", + "appSettings_timeFilterShowLast": "Pokaż węzły z ostatnich {hours} godzin", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Filtrowanie Czasu Mapy", + "appSettings_showNodesDiscoveredWithin": "Pokaż węzły odkryte w:", + "appSettings_allTime": "Wszystko czasowo", + "appSettings_lastHour": "Ostatnia godzina", + "appSettings_last6Hours": "Ostatnie 6 godzin", + "appSettings_last24Hours": "Ostatnie 24 godziny", + "appSettings_lastWeek": "Tydzień temu", + "appSettings_offlineMapCache": "Bufor Map Offline", + "appSettings_noAreaSelected": "Nie zaznaczono żadnej powierzchni.", + "appSettings_areaSelectedZoom": "Wybrany obszar (skala {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Debug", + "appSettings_appDebugLogging": "Logowanie Debugowania Aplikacji", + "appSettings_appDebugLoggingSubtitle": "Loguj wiadomości debugowania aplikacji w celu rozwiązywania problemów.", + "appSettings_appDebugLoggingEnabled": "Zdebugowanie aplikacji włączone", + "appSettings_appDebugLoggingDisabled": "Zasubskrybowane logi debugowania aplikacji wyłączone.", + "contacts_title": "Kontakty", + "contacts_noContacts": "Brak jeszcze kontaktów.", + "contacts_contactsWillAppear": "Kontakty będą wyświetlane, gdy urządzenia reklamują się.", + "contacts_searchContacts": "Wyszukaj kontakty...", + "contacts_noUnreadContacts": "Brak nieprzeczytanych kontaktów", + "contacts_noContactsFound": "Brak znalezionych kontaktów ani grup.", + "contacts_deleteContact": "Usuń Kontakt", + "contacts_removeConfirm": "Usuń {contactName} z kontaktów?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Zarządzaj Powtórzami", + "contacts_roomLogin": "Logowanie do pokoju", + "contacts_openChat": "Otwórz czat", + "contacts_editGroup": "Edytuj Grupę", + "contacts_deleteGroup": "Usuń Grupę", + "contacts_deleteGroupConfirm": "Usuń \"{groupName}\"?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Nowa Grupa", + "contacts_groupName": "Nazwa grupy", + "contacts_groupNameRequired": "Nazwa grupy jest wymagana", + "contacts_groupAlreadyExists": "Grupa \"{name}\" już istnieje", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Filtruj kontakty...", + "contacts_noContactsMatchFilter": "Brak pasujących kontaktów do Twojego filtra", + "contacts_noMembers": "Brak członków", + "contacts_lastSeenNow": "Ostatnie połączenie", + "contacts_lastSeenMinsAgo": "Ostatnie połączenie {minutes} min temu", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Ostatni raz widziany 1 godzinę temu", + "contacts_lastSeenHoursAgo": "Ostatnie połączenie {hours} godzin temu", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Ostatni raz widziany 1 dzień temu", + "contacts_lastSeenDaysAgo": "Ostatnie połączenie {days} dni temu", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Kanały", + "channels_noChannelsConfigured": "Brak skonfigurowanych kanałów", + "channels_addPublicChannel": "Dodaj kanał publiczny", + "channels_searchChannels": "Wyszukaj kanały...", + "channels_noChannelsFound": "Brak znalezionych kanałów", + "channels_channelIndex": "Kanał {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Kanał z hashtagami", + "channels_public": "Publiczny", + "channels_private": "Prywatne", + "channels_publicChannel": "Kanał publiczny", + "channels_privateChannel": "Prywatny kanał", + "channels_editChannel": "Edytuj kanał", + "channels_deleteChannel": "Usuń kanał", + "channels_deleteChannelConfirm": "Usuń \"{name}\"? Nie można tego cofnąć.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Kanał \"{name}\" usunięto", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Dodaj Kanał", + "channels_channelIndexLabel": "Indeks kanału", + "channels_channelName": "Nazwa kanału", + "channels_usePublicChannel": "Użyj kanału publicznego", + "channels_standardPublicPsk": "Standard public PSK", + "channels_pskHex": "PSK (Hex)", + "channels_generateRandomPsk": "Wygeneruj losowy klucz PSK", + "channels_enterChannelName": "Proszę podać nazwę kanału.", + "channels_pskMustBe32Hex": "PSK musi mieć 32 znaki szesnastkowe.", + "channels_channelAdded": "Kanał \"{name}\" dodany", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Edytuj Kanał {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "Kompresja SMAZ", + "channels_channelUpdated": "Kanał \"{name}\" został zaktualizowany", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "Kanał publiczny dodany", + "channels_sortBy": "Sortuj po", + "channels_sortManual": "Ręczna", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "Najnowsze wiadomości", + "channels_sortUnread": "Niezgłoszone", + "chat_noMessages": "Brak jeszcze wiadomości", + "chat_sendMessageToStart": "Wyślij wiadomość, aby rozpocząć.", + "chat_originalMessageNotFound": "Błąd: Nie znaleziono oryginalnego komunikatu", + "chat_replyingTo": "Odpowiadanie na {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Odpowiedz {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Lokalizacja", + "chat_sendMessageTo": "Wyślij wiadomość do {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Wpisz wiadomość...", + "chat_messageTooLong": "Wiadomość jest za długa (maksymalnie {maxBytes} bajtów).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Wiadomość skopiowana", + "chat_messageDeleted": "Wiadomość usunięta", + "chat_retryingMessage": "Próba ponowienia", + "chat_retryCount": "Spróbuj {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "Wyślij GIF", + "chat_reply": "Odpowiedz", + "chat_addReaction": "Dodaj Reakcję", + "chat_me": "Ja", + "emojiCategorySmileys": "Emoji", + "emojiCategoryGestures": "Gestikulacje", + "emojiCategoryHearts": "Serce", + "emojiCategoryObjects": "Obiekty", + "gifPicker_title": "Wybierz GIF", + "gifPicker_searchHint": "Wyszukaj GIF-y...", + "gifPicker_poweredBy": "Zasilane przez GIPHY", + "gifPicker_noGifsFound": "Nie znaleziono GIF-ów", + "gifPicker_failedLoad": "Nie udało się załadować GIF-ów", + "gifPicker_failedSearch": "Nie udało się znaleźć GIF-ów", + "gifPicker_noInternet": "Brak połączenia internetowego", + "debugLog_appTitle": "Log Wykonywania Aplikacji", + "debugLog_bleTitle": "Log błędów BLE", + "debugLog_copyLog": "Kopiuj log", + "debugLog_clearLog": "Wyczyść dziennik", + "debugLog_copied": "Skopiowano dziennik debugowania", + "debugLog_bleCopied": "Skopiowany log BLE", + "debugLog_noEntries": "Nie ma jeszcze żadnych logów debugowania.", + "debugLog_enableInSettings": "Włącz logowanie debugowania aplikacji w ustawieniach", + "debugLog_frames": "Ramy", + "debugLog_rawLogRx": "Surowe Log-RX", + "debugLog_noBleActivity": "Brak aktywności BLE jeszcze.", + "debugFrame_length": "Długość ramy: {count} bajtów", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Polecenie: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Wiadomość tekstowa:", + "debugFrame_destinationPubKey": "- Oznaczenie PubKey: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Timestamp: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Flagi: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- Typ tekstu: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Proste", + "debugFrame_text": "- Tekst: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Wyjście SzESZCZNULNE:", + "chat_pathManagement": "Zarządzanie ścieżkami", + "chat_routingMode": "Tryb routingu", + "chat_autoUseSavedPath": "Automatyczne (użyj zapisanej ścieżki)", + "chat_forceFloodMode": "Wymusz Tryb Powodowany", + "chat_recentAckPaths": "Ostatnie ścieżki ACK (naciśnij, aby użyć):", + "chat_pathHistoryFull": "Historia ścieżek jest pełna. Usuń wpisy, aby dodać nowe.", + "chat_hopSingular": "Skacz", + "chat_hopPlural": "skoczkowie", + "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "Sukcesy", + "chat_removePath": "Usuń ścieżkę", + "chat_noPathHistoryYet": "Brak jeszcze historii ścieżek.\nWyślij wiadomość, aby odkryć ścieżki.", + "chat_pathActions": "Działania ścieżki:", + "chat_setCustomPath": "Ustaw Ścieżkę Dostosowaną", + "chat_setCustomPathSubtitle": "Ręcznie określ trasę.", + "chat_clearPath": "Wyczyść Ścieżkę", + "chat_clearPathSubtitle": "Zmusz do ponownej identyfikacji przy następnym wysłaniu", + "chat_pathCleared": "Ścieżka oczyszczona. Kolejne powiadomienie odnajdzie trasę.", + "chat_floodModeSubtitle": "Użyj przełącznika routingu w pasku narzędzi.", + "chat_floodModeEnabled": "Tryb powodziowy włączony. Włącz ponownie za pomocą ikony routingu w pasku narzędzi.", + "chat_fullPath": "Pełna ścieżka", + "chat_pathDetailsNotAvailable": "Szczegóły ścieżki jeszcze niedostępne. Spróbuj wysłać wiadomość, aby odświeżyć.", + "chat_pathSetHops": "Ścieżka ustawiona: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Zapisano lokalnie. Połącz się, aby zsynchronizować.", + "chat_pathDeviceConfirmed": "Urządzenie potwierdzone.", + "chat_pathDeviceNotConfirmed": "Urządzenie nie zostało jeszcze potwierdzone.", + "chat_type": "Wprowadź", + "chat_path": "Ścieżka", + "chat_publicKey": "Klucz Publiczny", + "chat_compressOutgoingMessages": "Kompresuj wychodzące wiadomości", + "chat_floodForced": "Powodowana Powódź", + "chat_directForced": "Bezpośrednio (wymuszono)", + "chat_hopsForced": "{count} skoków (wymuszonych)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Powodzie (automatyczne)", + "chat_direct": "Bezpośrednio", + "chat_poiShared": "Wspólny POI", + "chat_unread": "Niezgłoszone: {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Mapa węzłów", + "map_noNodesWithLocation": "Brak węzłów z danymi lokalizacyjnymi", + "map_nodesNeedGps": "Węzły muszą udostępniać swoje współrzędne GPS,\naby pojawić się na mapie.", + "map_nodesCount": "Węzły: {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Pinki: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Rozmowa", + "map_repeater": "Powtórzacz", + "map_room": "Pokój", + "map_sensor": "Czujnik", + "map_pinDm": "Zablokuj (DM)", + "map_pinPrivate": "Zablokuj (Prywatnie)", + "map_pinPublic": "Oznacz jako publiczne", + "map_lastSeen": "Ostatni raz widziany", + "map_disconnectConfirm": "Czy na pewno chcesz się odłączyć od tego urządzenia?", + "map_from": "Od", + "map_source": "Źródło", + "map_flags": "Flagi", + "map_shareMarkerHere": "Udostępnij znacznik tutaj", + "map_pinLabel": "Oznacz etykietę", + "map_label": "Etykieta", + "map_pointOfInterest": "Punkt zainteresowań", + "map_sendToContact": "Wyślij do kontaktu", + "map_sendToChannel": "Wyślij do kanału", + "map_noChannelsAvailable": "Brak dostępnych kanałów", + "map_publicLocationShare": "Udostępnij lokalizację publicznie", + "map_publicLocationShareConfirm": "Wkrótce udostępnisz lokalizację w {channelLabel}. Ten kanał jest publiczny i każdy z PSK może go zobaczyć.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Połącz się z urządzeniem, aby udostępniać znacznik.", + "map_filterNodes": "Filtruj Węzły", + "map_nodeTypes": "Typy węzłów", + "map_chatNodes": "Węzły czatu", + "map_repeaters": "Powtarzacze", + "map_otherNodes": "Inne węzły", + "map_keyPrefix": "Prefiks klucza", + "map_filterByKeyPrefix": "Filtruj po prefiksie klucza", + "map_publicKeyPrefix": "Przewód klucza publicznego", + "map_markers": "Oznaczarki", + "map_showSharedMarkers": "Pokaż współdzielone znaki.", + "map_lastSeenTime": "Ostatni raz widiany", + "map_sharedPin": "Podzielony PIN", + "map_joinRoom": "Dołącz do pokoju", + "map_manageRepeater": "Zarządzaj Powtórzami", + "mapCache_title": "Bufor Map Offline", + "mapCache_selectAreaFirst": "Wybierz obszar do wstępnego pobrania.", + "mapCache_noTilesToDownload": "Brak dostępnych płytek do pobrania dla tego obszaru.", + "mapCache_downloadTilesTitle": "Pobierz płytki", + "mapCache_downloadTilesPrompt": "Pobierz {count} płytek do użytku offline?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Pobierz", + "mapCache_cachedTiles": "Pamiętanych {count} płytek", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Pamiętane {downloaded} płytki ({failed} nieudane)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Wyczyść pamięć podręczną offline", + "mapCache_clearOfflineCachePrompt": "Usuń wszystkie tymczasowe kafelki mapy?", + "mapCache_offlineCacheCleared": "Pamięć podręczna offline została wyczyszczona", + "mapCache_noAreaSelected": "Nie zaznaczono żadnej powierzchni.", + "mapCache_cacheArea": "Obszar pamięci podręcznej", + "mapCache_useCurrentView": "Użyj aktualnego widoku", + "mapCache_zoomRange": "Zakres powiększenia", + "mapCache_estimatedTiles": "Szacunkowa liczba płytek: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Pobrano {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Pobierz Paski", + "mapCache_clearCacheButton": "Wyczyść pamięć podręczną", + "mapCache_failedDownloads": "Nieudane pobrania: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Właśnie teraz", + "time_minutesAgo": "{minutes} minut temu", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours}h temu", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} dni temu", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "godzina", + "time_hours": "godziny", + "time_day": "dzień", + "time_days": "dni", + "time_week": "tydzień", + "time_weeks": "tygodnie", + "time_month": "miesiąc", + "time_months": "miesiace", + "time_minutes": "minuty", + "time_allTime": "Wszystko czasowo", + "dialog_disconnect": "Odłącz", + "dialog_disconnectConfirm": "Czy na pewno chcesz się odłączyć od tego urządzenia?", + "login_repeaterLogin": "Powtórz Logowanie", + "login_roomLogin": "Logowanie do pokoju", + "login_password": "Hasło", + "login_enterPassword": "Wprowadź hasło", + "login_savePassword": "Zapisz hasło", + "login_savePasswordSubtitle": "Hasło będzie bezpiecznie przechowywane na tym urządzeniu.", + "login_repeaterDescription": "Wprowadź hasło do powtarzacza, aby uzyskać dostęp do ustawień i statusu.", + "login_roomDescription": "Wprowadź hasło do pokoju, aby uzyskać dostęp do ustawień i statusu.", + "login_routing": "Przekierowanie", + "login_routingMode": "Tryb routingu", + "login_autoUseSavedPath": "Automatycznie (użyj zapisanej ścieżki)", + "login_forceFloodMode": "Wymusz Tryb Powodowany", + "login_managePaths": "Zarządzaj Ścieżkami", + "login_login": "Zaloguj się", + "login_attempt": "Próba {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Zalogowanie się nie powiodło: {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Ponownie załadować", + "common_clear": "Wyczyść", + "path_currentPath": "Aktualny ścieżka: {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Użyj ścieżki {count} {count, plural, =1{hop} other{hops}}.", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Wprowadź własną ścieżkę", + "path_currentPathLabel": "Aktualny ścieżka", + "path_hexPrefixInstructions": "Wprowadź 2-znakowe prefiksy szesnastkowe dla każdego skoku, oddzielone przecinkami.", + "path_hexPrefixExample": "A1,F2,3C (każedy węzeł używa pierwszego bajtu swojego klucza publicznego)", + "path_labelHexPrefixes": "Ścieżka (przesunięcia bitowe)", + "path_helperMaxHops": "Maksymalnie 64 skoki. Każda prefiks ma 2 znaki szesnastkowe (1 bajt).", + "path_selectFromContacts": "Albo wybierz z kontaktów:", + "path_noRepeatersFound": "Nie znaleziono repeaterów ani serwerów pokoi.", + "path_customPathsRequire": "Dostosowane ścieżki wymagają pośrednich skoków, które mogą przekazywać wiadomości.", + "path_invalidHexPrefixes": "Nieprawidłowe prefiksy szesnastkowe: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "Ścieżka jest zbyt długa. Dozwolonych skoków wynosi 64.", + "path_setPath": "Ustaw Ścieżkę", + "repeater_management": "Zarządzanie Powtórzami", + "repeater_managementTools": "Narzędzia Zarządzania", + "repeater_status": "Status", + "repeater_statusSubtitle": "Wyświetl status powtarzacza, statystyki i sąsiadów.", + "repeater_telemetry": "Telemetry", + "repeater_telemetrySubtitle": "Wyświetl dane telemetryczne z czujników i statystyki systemu", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Wyślij polecenia do powielacza", + "repeater_settings": "Ustawienia", + "repeater_settingsSubtitle": "Skonfiguruj parametry powtarzacza", + "repeater_statusTitle": "Status powtarzacza", + "repeater_routingMode": "Tryb routingu", + "repeater_autoUseSavedPath": "Automatycznie (użyj zapisanej ścieżki)", + "repeater_forceFloodMode": "Wymusz Tryb Powodowany", + "repeater_pathManagement": "Zarządzanie ścieżkami", + "repeater_refresh": "Odśwież", + "repeater_statusRequestTimeout": "Życzenie statusu timed out.", + "repeater_errorLoadingStatus": "Błąd podczas ładowania statusu: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Informacje o systemie", + "repeater_battery": "Bateria", + "repeater_clockAtLogin": "Godzina (przy logowaniu)", + "repeater_uptime": "Dostępność", + "repeater_queueLength": "Długość kolejki", + "repeater_debugFlags": "Opcje debugowania", + "repeater_radioStatistics": "Statystyki Radia", + "repeater_lastRssi": "Ostatni RSSI", + "repeater_lastSnr": "Ostatnie SNR", + "repeater_noiseFloor": "Poziom Szumów", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Statystyki pakietów", + "repeater_sent": "Wysłane", + "repeater_received": "Otrzymano", + "repeater_duplicates": "Powtórzenia", + "repeater_daysHoursMinsSecs": "{days} dni {hours}h {minutes}m {seconds}s", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Razem: {total}, Powodzenie: {flood}, Bezpośrednio: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Razem: {total}, Powodzenie: {flood}, Bezpośrednio: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Powodzie: {flood}, Bezpośrednie: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Razem: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Ustawienia Powtórki", + "repeater_basicSettings": "Podstawowe Ustawienia", + "repeater_repeaterName": "Nazwa Powtórnika", + "repeater_repeaterNameHelper": "Wyświetl nazwę tego powtarzacza", + "repeater_adminPassword": "Hasło Administracyjne", + "repeater_adminPasswordHelper": "Pełny dostęp hasło", + "repeater_guestPassword": "Hasło gościa", + "repeater_guestPasswordHelper": "Dostęp tylko do odczytu hasło", + "repeater_radioSettings": "Ustawienia radia", + "repeater_frequencyMhz": "Częstotliwość (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Power", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Przepustowość", + "repeater_spreadingFactor": "Rozkład Czynnika", + "repeater_codingRate": "Stawka kodowania", + "repeater_locationSettings": "Ustawienia Lokalizacji", + "repeater_latitude": "Szerokość", + "repeater_latitudeHelper": "Stopnie dziesiętne (np. 37.7749)", + "repeater_longitude": "Długość", + "repeater_longitudeHelper": "Stopnie dziesiętne (np. -122,4194)", + "repeater_features": "Funkcje", + "repeater_packetForwarding": "Przekierowanie pakietów", + "repeater_packetForwardingSubtitle": "Włącz repeater, aby przekazywać pakiety.", + "repeater_guestAccess": "Dostęp dla gości", + "repeater_guestAccessSubtitle": "Umożliw dostęp tylko do odczytu dla gości.", + "repeater_privacyMode": "Tryb Prywatności", + "repeater_privacyModeSubtitle": "Ukryj imię/lokalizację w reklamach", + "repeater_advertisementSettings": "Ustawienia Reklam", + "repeater_localAdvertInterval": "Interwał Reklamy Lokalnej", + "repeater_localAdvertIntervalMinutes": "{minutes} minut", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Interwał Reklamy Powodziowej", + "repeater_floodAdvertIntervalHours": "{hours} godzin", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Zaszyfrowany Interwał Reklamowy", + "repeater_dangerZone": "Strefa Zagrożeń", + "repeater_rebootRepeater": "Zrestartuj Powtarzacz", + "repeater_rebootRepeaterSubtitle": "Zrestartuj urządzenie powtarzające.", + "repeater_rebootRepeaterConfirm": "Czy na pewno chcesz zrestartować ten repeater?", + "repeater_regenerateIdentityKey": "Wygeneruj klucz tożsamości", + "repeater_regenerateIdentityKeySubtitle": "Wygeneruj nową parę kluczy publicznych/prywatnych", + "repeater_regenerateIdentityKeyConfirm": "To zostanie wygenerowane nowe tożsamość dla powtarzacza. Kontynuować?", + "repeater_eraseFileSystem": "Wyczyść System Plików", + "repeater_eraseFileSystemSubtitle": "Sformatuj system plików powielacza", + "repeater_eraseFileSystemConfirm": "OSTRZEŻENIE: To spowoduje usunięcie wszystkich danych z powtarzacza. Nie da się tego cofnąć!", + "repeater_eraseSerialOnly": "Usunięcie jest dostępne tylko przez konsolę szeregową.", + "repeater_commandSent": "Polecenie wysłane: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Błąd podczas wysyłania polecenia: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "Potwierdź", + "repeater_settingsSaved": "Ustawienia zostały pomyślnie zapisane.", + "repeater_errorSavingSettings": "Błąd zapisu ustawień: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Odśwież Podstawowe Ustawienia", + "repeater_refreshRadioSettings": "Odśwież Ustawienia Radio", + "repeater_refreshTxPower": "Odśwież TX power", + "repeater_refreshLocationSettings": "Odśwież Ustawienia Lokalizacji", + "repeater_refreshPacketForwarding": "Odśwież trasowanie pakietów", + "repeater_refreshGuestAccess": "Odśwież dostęp gościa", + "repeater_refreshPrivacyMode": "Odśwież Tryb Prywatności", + "repeater_refreshAdvertisementSettings": "Odśwież Ustawienia Reklamy", + "repeater_refreshed": "{label} odświeżone", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Błąd podczas odświeżania {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Powtarzacz CLI", + "repeater_debugNextCommand": "Debug Następną Komendę", + "repeater_commandHelp": "Pomoc", + "repeater_clearHistory": "Wyczyść historię", + "repeater_noCommandsSent": "Nie wysłano jeszcze żadnych poleceń", + "repeater_typeCommandOrUseQuick": "Wprowadź polecenie poniżej lub użyj szybkich poleceń", + "repeater_enterCommandHint": "Wprowadź polecenie...", + "repeater_previousCommand": "Poprzednia komenda", + "repeater_nextCommand": "Następna komenda", + "repeater_enterCommandFirst": "Wprowadź najpierw polecenie", + "repeater_cliCommandFrameTitle": "Określony Wyraz Polecenia CLI", + "repeater_cliCommandError": "Błąd: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Pobierz imię", + "repeater_cliQuickGetRadio": "Uzyskaj Radio", + "repeater_cliQuickGetTx": "Pobierz TX", + "repeater_cliQuickNeighbors": "Sąsiedzi", + "repeater_cliQuickVersion": "Wersja", + "repeater_cliQuickAdvertise": "Reklama", + "repeater_cliQuickClock": "Godzina", + "repeater_cliHelpAdvert": "Wysyła pakiet reklamowy", + "repeater_cliHelpReboot": "Zresetuj urządzenie. (Uwaga, może pojawić się 'Timeout', co jest normalne)", + "repeater_cliHelpClock": "Wyświetla aktualny czas zgodnie z zegarem urządzenia.", + "repeater_cliHelpPassword": "Ustawia nowe hasło administratora dla urządzenia.", + "repeater_cliHelpVersion": "Wyświetla wersję urządzenia i datę budowy oprogramowania.", + "repeater_cliHelpClearStats": "Resetuje różne wskaźniki statystyk do zera.", + "repeater_cliHelpSetAf": "Ustawia czynnik czasu powietrznego.", + "repeater_cliHelpSetTx": "Ustawia moc transmisji LoRa w dBm. (zrestartuj, aby zastosować)", + "repeater_cliHelpSetRepeat": "Włącza lub wyłącza rolę powtarzacza dla tego węzła.", + "repeater_cliHelpSetAllowReadOnly": "(Serwer pokoju) Jeśli 'włączone', to logowanie z pustym hasłem będzie dozwolone, ale nie można publikować w pokoju (tylko czytać).", + "repeater_cliHelpSetFloodMax": "Ustawia maksymalną liczbę skoków pakietu powrotnego (jeśli >= max, pakiet nie jest przekierowywany)", + "repeater_cliHelpSetIntThresh": "Ustawia Próg Interferencji (w dB). Domyślnie wynosi 14. Ustaw na 0, aby wyłączyć wykrywanie zakłóceń kanału.", + "repeater_cliHelpSetAgcResetInterval": "Ustawia interwał do zresetowania Automatycznego Sterownika Głośności. Ustaw na 0, aby wyłączyć.", + "repeater_cliHelpSetMultiAcks": "Włącza lub wyłącza funkcję 'podwójnych potwierdzeń'.", + "repeater_cliHelpSetAdvertInterval": "Ustawia interwał timera w minutach do wysyłania pakietu reklamy lokalnej (bezpośredniej). Ustaw na 0, aby wyłączyć.", + "repeater_cliHelpSetFloodAdvertInterval": "Ustawia interwał timera w godzinach do wysłania pakietu reklamowego typu \"powiew\". Ustaw na 0, aby wyłączyć.", + "repeater_cliHelpSetGuestPassword": "Ustawia/aktualizuje hasło gościa. (dla repeaterów, loginy gości mogą wysyłać żądanie \"Get Stats\")", + "repeater_cliHelpSetName": "Ustawia nazwę reklamy.", + "repeater_cliHelpSetLat": "Ustawia współrzędną geograficzne (w stopniach dziesiętnych) mapy reklam.", + "repeater_cliHelpSetLon": "Ustawia współrzędną długościową mapy reklamy. (stopnie dziesiętne)", + "repeater_cliHelpSetRadio": "Ustawia nowe parametry radia i zapisuje je w preferencjach. Wymaga polecenia \"reboot\" do zastosowania.", + "repeater_cliHelpSetRxDelay": "Ustawienia (eksperymentalne) bazowe (muszą być > 1, aby działać) do stosowania lekkiego opóźnienia dla odebranych pakietów, w oparciu o siłę sygnału/wynik. Ustaw na 0, aby wyłączyć.", + "repeater_cliHelpSetTxDelay": "Ustawia czynnik mnożony przez czas utrzymania w trybie zalewowym dla pakietu oraz z wykorzystaniem losowego systemu slotów, aby opóźnić jego przesyłanie (zmniejszając prawdopodobieństwo kolizji).", + "repeater_cliHelpSetDirectTxDelay": "Taki sam jak txdelay, ale dla stosowania losowej opóźnienia przy przekazywaniu pakietów w trybie bezpośrednim.", + "repeater_cliHelpSetBridgeEnabled": "Włącz/Wyłącz mostek.", + "repeater_cliHelpSetBridgeDelay": "Ustaw czas opóźnienia przed ponownym wysyłaniem pakietów.", + "repeater_cliHelpSetBridgeSource": "Wybierz, czy most będzie ponownie transmitował otrzymywane pakiety, czy też wysyłane.", + "repeater_cliHelpSetBridgeBaud": "Ustaw prędkość transmisji magistrali szeregowej dla mostów rs232.", + "repeater_cliHelpSetBridgeSecret": "Ustaw sekret dla mostów ESPNOW.", + "repeater_cliHelpSetAdcMultiplier": "Ustawia niestandardowy współczynnik do korekty zgłaszanego napięcia baterii (obsługa tylko na wybranych płytach).", + "repeater_cliHelpTempRadio": "Ustawia tymczasowe parametry radia na podany czas trwania w minutach, a następnie powraca do oryginalnych parametrów radia. (nie zapisuje zmian w preferencjach).", + "repeater_cliHelpSetPerm": "Modyfikuje ACL. Usuwa dopasowaną wpis (z prefiksem pubkey), jeśli \"permissions\" wynosi zero. Dodaje nowy wpis, jeśli pubkey-hex ma pełną długość i nie znajduje się obecnie w ACL. Aktualizuje wpis, dopasowując prefiks pubkey. Bit uprawnień zależy od roli firmware, ale dolne 2 bity to: 0 (Gość), 1 (tylko odczyt), 2 (odczyt i zapis), 3 (administrator).", + "repeater_cliHelpGetBridgeType": "Uzyskano typ mostu: brak, rs232, espnow", + "repeater_cliHelpLogStart": "Rozpoczyna się logowanie pakietów do systemu plików.", + "repeater_cliHelpLogStop": "Zatrzymuje logowanie pakietów do systemu plików.", + "repeater_cliHelpLogErase": "Usuwa logi pakietów z systemu plików.", + "repeater_cliHelpNeighbors": "Wyświetla listę innych węzłów powtarzających się, które usłyszano dzięki reklamom zero-hop. Każda linia to: id-prefix-hex:timestamp:snr-times-4", + "repeater_cliHelpNeighborRemove": "Usuwa pierwszy pasujący wpis (z prefiksem pubkey (hex)) z listy sąsiadów.", + "repeater_cliHelpRegion": "(tylko seria) Wyświetla wszystkie zdefiniowane regiony i aktualne uprawnienia do powodzi.", + "repeater_cliHelpRegionLoad": "ZAPOMNIJ: to jest specjalne wywołanie wielokomendowe. Każda następna komenda jest nazwą regionu (wcięta spacjami, aby wskazywać hierarchię nadrzędną, z minimum jedną spacją). Zakończona wysłaniem pustej linii/komendy.", + "repeater_cliHelpRegionGet": "Wyszukuje region o podanej nazwie prefiksu (lub \"\" dla zakresu globalnego). Odpowiada \"-> region-name (parent-name) 'F'\"", + "repeater_cliHelpRegionPut": "Dodaje lub aktualizuje definicję regionu z podaną nazwą.", + "repeater_cliHelpRegionRemove": "Usuwa definicję regionu o podanej nazwie. (musi się dokładnie zgadzać i nie może mieć podregionów).", + "repeater_cliHelpRegionAllowf": "Ustawia uprawnienia 'P'łytkowe dla podanego regionu. ('' dla zakresu globalnego/starszego)", + "repeater_cliHelpRegionDenyf": "Usuwa uprawnienie 'Pływające' dla podanej strefy. (ZALECANE: na tym etapie NIE zaleca się używania tego na globalnym/starszym zakresie!!).", + "repeater_cliHelpRegionHome": "Odpowiada z aktualnej 'home' region. (Uwaga: nie zostało jeszcze zastosowane, zarezerwowane na przyszłość).", + "repeater_cliHelpRegionHomeSet": "Ustawia region 'domowe'.", + "repeater_cliHelpRegionSave": "Zapisuje listę/mapę regionów do pamięci.", + "repeater_cliHelpGps": "Wyświetla status GPS. Jeśli GPS jest wyłączony, odpowiada tylko \"off\", jeśli jest włączony, odpowiada z \"on\", \"status\", \"fix\", liczbą satelitów.", + "repeater_cliHelpGpsOnOff": "Włącza/wyłącza nawigację GPS.", + "repeater_cliHelpGpsSync": "Synchronizuje czas węzła z zegarem GPS.", + "repeater_cliHelpGpsSetLoc": "Ustawia pozycję węzła na współrzędne GPS i zapisuje preferencje.", + "repeater_cliHelpGpsAdvert": "Udostępnia konfigurację reklamy lokalizacji węzła:\n- brak: nie uwzględniaj lokalizacji w reklamach\n- udostępnia: udostępnia lokalizację GPS (z SensorManager)\n- ustawienia: reklamuj lokalizację przechowywaną w ustawieniach", + "repeater_cliHelpGpsAdvertSet": "Ustawia konfigurację reklamy w lokalizacji.", + "repeater_commandsListTitle": "Lista poleceń", + "repeater_commandsListNote": "ZAPAMIĘTAJ: dla różnych poleceń \"set ...\" istnieje również polecenie \"get ...\".", + "repeater_general": "Ogólne", + "repeater_settingsCategory": "Ustawienia", + "repeater_bridge": "Most", + "repeater_logging": "Rejestrowanie", + "repeater_neighborsRepeaterOnly": "Sąsiedzi (tylko powtarzacz)", + "repeater_regionManagementRepeaterOnly": "Zarządzanie Regionem (tylko Powtarzacz)", + "repeater_regionNote": "Wprowadzono komendy regionalne w celu zarządzania definicjami i uprawnieniami regionów.", + "repeater_gpsManagement": "Zarządzanie GPS", + "repeater_gpsNote": "Polecenie GPS zostało wprowadzone w celu zarządzania tematami związanymi z lokalizacją.", + "telemetry_receivedData": "Otrzymano Dane Telemetrii", + "telemetry_requestTimeout": "Życzenie o danych telemetrycznych nie udało się.", + "telemetry_errorLoading": "Błąd podczas ładowania telemetry: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "Brak dostępnych danych telemetrycznych.", + "telemetry_channelTitle": "Kanał {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Bateria", + "telemetry_voltageLabel": "Napięcie", + "telemetry_mcuTemperatureLabel": "Temperatura MCU", + "telemetry_temperatureLabel": "Temperatura", + "telemetry_currentLabel": "Obecny", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}W", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Ścieżka pakietu", + "channelPath_viewMap": "Wyświetl mapę", + "channelPath_otherObservedPaths": "Inne Zauważone Ścieżki", + "channelPath_repeaterHops": "Skoki Powtórki", + "channelPath_noHopDetails": "Szczegóły dotyczące tego pakietu nie zostały podane.", + "channelPath_messageDetails": "Szczegóły wiadomości", + "channelPath_senderLabel": "Nadawca", + "channelPath_timeLabel": "Czas", + "channelPath_repeatsLabel": "Powtórzenia", + "channelPath_pathLabel": "Ścieżka {index}", + "channelPath_observedLabel": "Obserwowane", + "channelPath_observedPathTitle": "Obserwowany ścieżka {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "Brak danych lokalizacyjnych", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Nieznane", + "channelPath_floodPath": "Powodzenie", + "channelPath_directPath": "Bezpośrednio", + "channelPath_observedZeroOf": "0 z {total} skoków", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} z {total} skoków", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Mapa ścieżek", + "channelPath_noRepeaterLocations": "Brak dostępnych lokalizacji powtarzaczy dla tego ścieżki.", + "channelPath_primaryPath": "Ścieżka {index} (Główna)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Ścieżka", + "channelPath_observedPathHeader": "Obserwowana ścieżka", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "Brak dostępnych szczegółów hopa dla tego pakietu.", + "channelPath_unknownRepeater": "Nieznany Powtarzacz", + "listFilter_tooltip": "Filtruj i sortuj", + "listFilter_sortBy": "Sortuj po", + "listFilter_latestMessages": "Najnowsze wiadomości", + "listFilter_heardRecently": "Słyszano niedawno", + "listFilter_az": "A-Z", + "listFilter_filters": "Filtry", + "listFilter_all": "Wszystko", + "listFilter_users": "Użytkownicy", + "listFilter_repeaters": "Powtarzacze", + "listFilter_roomServers": "Serwery pokoju", + "listFilter_unreadOnly": "Tylko nieprzeczytane", + "listFilter_newGroup": "Nowa grupa" +} diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb new file mode 100644 index 0000000..59f4a47 --- /dev/null +++ b/lib/l10n/app_pt.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "pt", + "appTitle": "MeshCore Open", + "nav_contacts": "Contactos", + "nav_channels": "Canais", + "nav_map": "Mapa", + "common_cancel": "Cancelar", + "common_connect": "Conectar", + "common_unknownDevice": "Dispositivo Desconhecido", + "common_save": "Salvar", + "common_delete": "Excluir", + "common_close": "Fechar", + "common_edit": "Editar", + "common_add": "Adicionar", + "common_settings": "Configurações", + "common_disconnect": "Desconectar", + "common_connected": "Conectado", + "common_disconnected": "Desconectado", + "common_create": "Criar", + "common_continue": "Continuar", + "common_share": "Compartilhar", + "common_copy": "Copiar", + "common_retry": "Tentar novamente", + "common_hide": "Esconder", + "common_remove": "Remover", + "common_enable": "Ativar", + "common_disable": "Desativar", + "common_reboot": "Reiniciar", + "common_loading": "Carregando...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Procurando por dispositivos...", + "scanner_connecting": "Conectando...", + "scanner_disconnecting": "Desconectando...", + "scanner_notConnected": "Não está conectado", + "scanner_connectedTo": "Conectado a {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Procurando dispositivos MeshCore...", + "scanner_tapToScan": "Toque em \"Escanear\" para encontrar dispositivos MeshCore", + "scanner_connectionFailed": "Falha na conexão: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Pare", + "scanner_scan": "Digitalizar", + "device_quickSwitch": "Mudar rapidamente", + "device_meshcore": "MeshCore", + "settings_title": "Configurações", + "settings_deviceInfo": "Informações do Dispositivo", + "settings_appSettings": "Configurações do App", + "settings_appSettingsSubtitle": "Notificações, mensagens e preferências de mapa", + "settings_nodeSettings": "Configurações do Nó", + "settings_nodeName": "Nome do Nó", + "settings_nodeNameNotSet": "Não definido", + "settings_nodeNameHint": "Insira o nome do nó", + "settings_nodeNameUpdated": "Nome atualizado", + "settings_radioSettings": "Configurações de Rádio", + "settings_radioSettingsSubtitle": "Frequência, potência, fator de espalhamento", + "settings_radioSettingsUpdated": "Configurações de rádio atualizadas", + "settings_location": "Localização", + "settings_locationSubtitle": "Coordenadas GPS", + "settings_locationUpdated": "Localização atualizada", + "settings_locationBothRequired": "Insira a latitude e a longitude.", + "settings_locationInvalid": "Latitude ou longitude inválidos.", + "settings_latitude": "Latitude", + "settings_longitude": "Longitude", + "settings_privacyMode": "Modo de Privacidade", + "settings_privacyModeSubtitle": "Esconder nome/localização em anúncios", + "settings_privacyModeToggle": "Ative o modo de privacidade para ocultar seu nome e localização em anúncios.", + "settings_privacyModeEnabled": "Modo de privacidade ativado", + "settings_privacyModeDisabled": "Modo de privacidade desativado", + "settings_actions": "Ações", + "settings_sendAdvertisement": "Enviar Publicidade", + "settings_sendAdvertisementSubtitle": "Presença de transmissão agora", + "settings_advertisementSent": "Anúncio enviado", + "settings_syncTime": "Tempo de Sincronização", + "settings_syncTimeSubtitle": "Definir o relógio do dispositivo para o horário do telefone", + "settings_timeSynchronized": "Sincronizado com o tempo", + "settings_refreshContacts": "Atualizar Contatos", + "settings_refreshContactsSubtitle": "Recarregar a lista de contatos do dispositivo", + "settings_rebootDevice": "Reiniciar Dispositivo", + "settings_rebootDeviceSubtitle": "Reiniciar o dispositivo MeshCore", + "settings_rebootDeviceConfirm": "Tem certeza de que deseja reiniciar o dispositivo? Você será desconectado.", + "settings_debug": "Depurar", + "settings_bleDebugLog": "Log de Depuração BLE", + "settings_bleDebugLogSubtitle": "Comandos, respostas e dados brutos do BLE", + "settings_appDebugLog": "Log de Depuração do Aplicativo", + "settings_appDebugLogSubtitle": "Mensagens de depuração do aplicativo", + "settings_about": "Sobre", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "Projeto MeshCore de Código Aberto 2024", + "settings_aboutDescription": "Um cliente Flutter de código aberto para dispositivos de rede mesh LoRa Core da MeshCore.", + "settings_infoName": "Nome", + "settings_infoId": "ID", + "settings_infoStatus": "Status", + "settings_infoBattery": "Bateria", + "settings_infoPublicKey": "Chave Pública", + "settings_infoContactsCount": "Número de Contatos", + "settings_infoChannelCount": "Número do Canal", + "settings_presets": "Presets", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Frequência (MHz)", + "settings_frequencyHelper": "300,0 - 2500,0", + "settings_frequencyInvalid": "Frequência inválida (300-2500 MHz)", + "settings_bandwidth": "Largura de banda", + "settings_spreadingFactor": "Fator de Dispersão", + "settings_codingRate": "Taxa de Codificação", + "settings_txPower": "TX Potência (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Potência de TX inválida (0-22 dBm)", + "settings_longRange": "Alcance Longo", + "settings_fastSpeed": "Velocidade Rápida", + "settings_error": "Erro: {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "Configurações do App", + "appSettings_appearance": "Aparência", + "appSettings_theme": "Tema", + "appSettings_themeSystem": "Padrão do sistema", + "appSettings_themeLight": "Luz", + "appSettings_themeDark": "Escuro", + "appSettings_language": "Idioma", + "appSettings_languageSystem": "Padrão do sistema", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Notificações", + "appSettings_enableNotifications": "Ativar Notificações", + "appSettings_enableNotificationsSubtitle": "Receber notificações para mensagens e anúncios", + "appSettings_notificationPermissionDenied": "Permissão de notificação negada", + "appSettings_notificationsEnabled": "Notificações ativadas", + "appSettings_notificationsDisabled": "Notificações desativadas", + "appSettings_messageNotifications": "Notificações de Mensagem", + "appSettings_messageNotificationsSubtitle": "Mostrar notificação ao receber novas mensagens", + "appSettings_channelMessageNotifications": "Notificações de Mensagens do Canal", + "appSettings_channelMessageNotificationsSubtitle": "Mostrar notificação ao receber mensagens do canal", + "appSettings_advertisementNotifications": "Notificações de Anúncios", + "appSettings_advertisementNotificationsSubtitle": "Mostrar notificação quando novos nós forem descobertos", + "appSettings_messaging": "Mensagens", + "appSettings_clearPathOnMaxRetry": "Limpar Caminho em Tentativas Máximas", + "appSettings_clearPathOnMaxRetrySubtitle": "Redefinir o caminho de contato após 5 tentativas de envio falhas", + "appSettings_pathsWillBeCleared": "Os caminhos serão limpos após 5 tentativas falhas.", + "appSettings_pathsWillNotBeCleared": "Os caminhos não serão limpos automaticamente.", + "appSettings_autoRouteRotation": "Rotação de Rota Automática", + "appSettings_autoRouteRotationSubtitle": "Alternar entre os melhores caminhos e o modo inundação", + "appSettings_autoRouteRotationEnabled": "Rotação de roteamento automático habilitada", + "appSettings_autoRouteRotationDisabled": "Rotação de roteamento automático desativada", + "appSettings_battery": "Bateria", + "appSettings_batteryChemistry": "Química da Bateria", + "appSettings_batteryChemistryPerDevice": "Definir por dispositivo ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Conecte-se a um dispositivo para escolher", + "appSettings_batteryNmc": "18650 NMC (3,0-4,2V)", + "appSettings_batteryLifepo4": "LiFePO4 (2,6-3,65V)", + "appSettings_batteryLipo": "LiPo (3,0-4,2V)", + "appSettings_mapDisplay": "Exibição do Mapa", + "appSettings_showRepeaters": "Mostrar Repetidores", + "appSettings_showRepeatersSubtitle": "Exibir nós de repetidor no mapa", + "appSettings_showChatNodes": "Mostrar Nós de Chat", + "appSettings_showChatNodesSubtitle": "Exibir nós de chat no mapa", + "appSettings_showOtherNodes": "Mostrar Outros Nós", + "appSettings_showOtherNodesSubtitle": "Exibir outros tipos de nó no mapa", + "appSettings_timeFilter": "Filtro de Tempo", + "appSettings_timeFilterShowAll": "Mostrar todos os nós", + "appSettings_timeFilterShowLast": "Mostrar nós das últimas {hours} horas", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Filtro de Tempo do Mapa", + "appSettings_showNodesDiscoveredWithin": "Mostrar nós descobertos dentro de:", + "appSettings_allTime": "Todos os tempos", + "appSettings_lastHour": "Última hora", + "appSettings_last6Hours": "Últimos 6 horas", + "appSettings_last24Hours": "Últimas 24 horas", + "appSettings_lastWeek": "Da última semana", + "appSettings_offlineMapCache": "Cache de Mapa Offline", + "appSettings_noAreaSelected": "Nenhuma área selecionada", + "appSettings_areaSelectedZoom": "Área selecionada (zoom {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Depurar", + "appSettings_appDebugLogging": "Rastreamento de Depuração do Aplicativo", + "appSettings_appDebugLoggingSubtitle": "Registrar mensagens de depuração do aplicativo Log para solucionar problemas", + "appSettings_appDebugLoggingEnabled": "Log de depuração do aplicativo habilitado", + "appSettings_appDebugLoggingDisabled": "O registro de depuração do aplicativo está desativado.", + "contacts_title": "Contactos", + "contacts_noContacts": "Ainda não existem contatos.", + "contacts_contactsWillAppear": "Os contatos serão exibidos quando os dispositivos anunciarem.", + "contacts_searchContacts": "Pesquisar contatos...", + "contacts_noUnreadContacts": "Sem contatos não lidos.", + "contacts_noContactsFound": "Não foram encontrados contatos ou grupos.", + "contacts_deleteContact": "Excluir Contato", + "contacts_removeConfirm": "Remover {contactName} dos contatos?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Gerenciar Repetidor", + "contacts_roomLogin": "Login no Quarto", + "contacts_openChat": "Abrir Chat", + "contacts_editGroup": "Editar Grupo", + "contacts_deleteGroup": "Excluir Grupo", + "contacts_deleteGroupConfirm": "Remover {groupName}?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Novo Grupo", + "contacts_groupName": "Nome do grupo", + "contacts_groupNameRequired": "O nome do grupo é obrigatório.", + "contacts_groupAlreadyExists": "O grupo \"{name}\" já existe", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Filtrar contatos...", + "contacts_noContactsMatchFilter": "Não existem contatos que correspondam ao seu filtro", + "contacts_noMembers": "Nenhum membro", + "contacts_lastSeenNow": "Última vez que foi visto agora", + "contacts_lastSeenMinsAgo": "Última vez que foi visto {minutes} minutos atrás", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Última vez que foi visto há 1 hora.", + "contacts_lastSeenHoursAgo": "Última vez visto {hours} horas atrás", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Última vez que foi visto 1 dia atrás", + "contacts_lastSeenDaysAgo": "Última vez visto {days} dias atrás", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Canais", + "channels_noChannelsConfigured": "Nenhuma canalização configurada", + "channels_addPublicChannel": "Adicionar Canal Público", + "channels_searchChannels": "Pesquisar canais...", + "channels_noChannelsFound": "Nenhum canal encontrado", + "channels_channelIndex": "Canal {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Canal com hashtag", + "channels_public": "Público", + "channels_private": "Privado", + "channels_publicChannel": "Canal público", + "channels_privateChannel": "Canal privado", + "channels_editChannel": "Editar canal", + "channels_deleteChannel": "Excluir canal", + "channels_deleteChannelConfirm": "Excluir \"{name}\"? Não pode ser desfeito.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Canal \"{name}\" excluído", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Adicionar Canal", + "channels_channelIndexLabel": "Índice do Canal", + "channels_channelName": "Nome do Canal", + "channels_usePublicChannel": "Usar Canal Público", + "channels_standardPublicPsk": "PSK público padrão", + "channels_pskHex": "PSK (Hex)", + "channels_generateRandomPsk": "Gerar PSK aleatório", + "channels_enterChannelName": "Por favor, insira um nome de canal", + "channels_pskMustBe32Hex": "O PSK deve ter 32 caracteres hexadecimais.", + "channels_channelAdded": "Canal \"{name}\" adicionado", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Editar Canal {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "Compressão SMAZ", + "channels_channelUpdated": "Canal \"{name}\" atualizado", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "Canal público adicionado", + "channels_sortBy": "Ordenar por", + "channels_sortManual": "Manual", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "Últimas mensagens", + "channels_sortUnread": "Não lido", + "chat_noMessages": "Ainda não existem mensagens.", + "chat_sendMessageToStart": "Enviar uma mensagem para começar", + "chat_originalMessageNotFound": "Mensagem original não encontrada", + "chat_replyingTo": "Responder a {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Responder a {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Localização", + "chat_sendMessageTo": "Enviar uma mensagem para {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Digite uma mensagem...", + "chat_messageTooLong": "Mensagem muito longa (máximo {maxBytes} bytes).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Mensagem copiada", + "chat_messageDeleted": "Mensagem excluída", + "chat_retryingMessage": "Tentando novamente", + "chat_retryCount": "Tentar {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "Enviar GIF", + "chat_reply": "Responder", + "chat_addReaction": "Adicionar Reação", + "chat_me": "Eu", + "emojiCategorySmileys": "Emojis", + "emojiCategoryGestures": "Gestos", + "emojiCategoryHearts": "Corações", + "emojiCategoryObjects": "Objetos", + "gifPicker_title": "Escolher um GIF", + "gifPicker_searchHint": "Pesquisar GIFs...", + "gifPicker_poweredBy": "Desenvolvido por GIPHY", + "gifPicker_noGifsFound": "Nenhum GIF encontrado", + "gifPicker_failedLoad": "Não foi possível carregar os GIFs", + "gifPicker_failedSearch": "Falha na pesquisa de GIFs", + "gifPicker_noInternet": "Sem conexão com a internet", + "debugLog_appTitle": "Log de Depuração do Aplicativo", + "debugLog_bleTitle": "Log de Depuração BLE", + "debugLog_copyLog": "Copiar log", + "debugLog_clearLog": "Limpar log", + "debugLog_copied": "Log de depuração copiado", + "debugLog_bleCopied": "Log BLE copiado", + "debugLog_noEntries": "Ainda não existem logs de depuração.", + "debugLog_enableInSettings": "Ativar o log de depuração do aplicativo nas configurações", + "debugLog_frames": "Estruturas", + "debugLog_rawLogRx": "Log Raw-RX", + "debugLog_noBleActivity": "Ainda não há atividade BLE.", + "debugFrame_length": "Comprimento do Quadro: {count} bytes", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Comando: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Mensagem de Texto:", + "debugFrame_destinationPubKey": "- Destino PubKey: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Timestamp: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Bandeiras: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- Tipo de Texto: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Simples", + "debugFrame_text": "- Texto: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Espaço Hexadecimal:", + "chat_pathManagement": "Gerenciamento de Caminhos", + "chat_routingMode": "Modo de roteamento", + "chat_autoUseSavedPath": "Auto (usar caminho salvo)", + "chat_forceFloodMode": "Modo de Inundação Forçado", + "chat_recentAckPaths": "Rotas de ACK Recentes (toque para usar):", + "chat_pathHistoryFull": "O histórico está cheio. Remova entradas para adicionar novas.", + "chat_hopSingular": "pule", + "chat_hopPlural": "salta", + "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "Sucessos", + "chat_removePath": "Remover caminho", + "chat_noPathHistoryYet": "Ainda não há histórico de caminhos.\nEnvie uma mensagem para descobrir caminhos.", + "chat_pathActions": "Ações do Caminho:", + "chat_setCustomPath": "Definir Caminho Personalizado", + "chat_setCustomPathSubtitle": "Especifique manualmente o caminho de roteamento", + "chat_clearPath": "Limpar Caminho", + "chat_clearPathSubtitle": "Forçar a descoberta na próxima transmissão", + "chat_pathCleared": "Caminho limpo. A próxima mensagem redescobrirá a rota.", + "chat_floodModeSubtitle": "Use a chave de roteamento na barra de ferramentas", + "chat_floodModeEnabled": "Modo de inundação ativado. Desative-o novamente através do ícone de roteamento na barra de ferramentas.", + "chat_fullPath": "Caminho Completo", + "chat_pathDetailsNotAvailable": "Os detalhes do caminho ainda não estão disponíveis. Tente enviar uma mensagem para atualizar.", + "chat_pathSetHops": "Caminho definido: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Salvo localmente. Conectar para sincronizar.", + "chat_pathDeviceConfirmed": "Dispositivo confirmado.", + "chat_pathDeviceNotConfirmed": "Dispositivo ainda não confirmado.", + "chat_type": "Digite", + "chat_path": "Caminho", + "chat_publicKey": "Chave Pública", + "chat_compressOutgoingMessages": "Comprimir mensagens enviadas", + "chat_floodForced": "Inundação (forçada)", + "chat_directForced": "Direto (forçado)", + "chat_hopsForced": "{count} saltos (forçado)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Inundação (automática)", + "chat_direct": "Salvar", + "chat_poiShared": "Ponto de Interesse Compartilhado", + "chat_unread": "Não lido: {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Mapa de Nós", + "map_noNodesWithLocation": "Não existem nós com dados de localização.", + "map_nodesNeedGps": "Os nós precisam partilhar as suas coordenadas GPS\npara aparecerem no mapa", + "map_nodesCount": "Nós: {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Pinos: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Chat", + "map_repeater": "Repetidor", + "map_room": "Quarto", + "map_sensor": "Sensor", + "map_pinDm": "Gatilho (DM)", + "map_pinPrivate": "Bloquear (Privado)", + "map_pinPublic": "Pin (Público)", + "map_lastSeen": "Última Visão", + "map_disconnectConfirm": "Tem certeza de que deseja desconectar deste dispositivo?", + "map_from": "De", + "map_source": "Fonte", + "map_flags": "Bandeiras", + "map_shareMarkerHere": "Compartilhar marcador aqui", + "map_pinLabel": "Rótulo de marcador", + "map_label": "Rótulo", + "map_pointOfInterest": "Ponto de interesse", + "map_sendToContact": "Enviar para o contato", + "map_sendToChannel": "Enviar para o canal", + "map_noChannelsAvailable": "Não existem canais disponíveis.", + "map_publicLocationShare": "Compartilhar local público", + "map_publicLocationShareConfirm": "Você está prestes a compartilhar uma localização em {channelLabel}. Este canal é público e qualquer pessoa com a PSK pode visualizá-lo.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Conecte-se a um dispositivo para compartilhar marcadores", + "map_filterNodes": "Filtrar Nós", + "map_nodeTypes": "Tipos de Nó", + "map_chatNodes": "Nós de Chat", + "map_repeaters": "Repetidores", + "map_otherNodes": "Outros Nós", + "map_keyPrefix": "Prefixo Chave", + "map_filterByKeyPrefix": "Filtrar por prefixo-chave", + "map_publicKeyPrefix": "Prefixo de chave pública", + "map_markers": "Marcadores", + "map_showSharedMarkers": "Mostrar marcadores compartilhados", + "map_lastSeenTime": "Último Tempo de Visualização", + "map_sharedPin": "Pin compartilhado", + "map_joinRoom": "Junte-se à Sala", + "map_manageRepeater": "Gerenciar Repetidor", + "mapCache_title": "Cache de Mapa Offline", + "mapCache_selectAreaFirst": "Selecione uma área para armazenar em cache primeiro", + "mapCache_noTilesToDownload": "Não há tiles para baixar para esta área.", + "mapCache_downloadTilesTitle": "Baixar tiles", + "mapCache_downloadTilesPrompt": "Baixar {count} tiles para uso offline?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Baixar", + "mapCache_cachedTiles": "Armazenados {count} azulejos", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Tiles em cache ({downloaded}) ({failed} falhou)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Limpar cache offline", + "mapCache_clearOfflineCachePrompt": "Remover todas as telhas de mapa em cache?", + "mapCache_offlineCacheCleared": "Cache offline limpa", + "mapCache_noAreaSelected": "Nenhuma área selecionada", + "mapCache_cacheArea": "Área de Cache", + "mapCache_useCurrentView": "Usar a Visualização Atual", + "mapCache_zoomRange": "Intervalo de Zoom", + "mapCache_estimatedTiles": "Estimados azulejos: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Baixado {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Baixar Tiles", + "mapCache_clearCacheButton": "Limpar Cache", + "mapCache_failedDownloads": "Downloads falhas: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Agora", + "time_minutesAgo": "{minutes} minutos atrás", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours}h atrás", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} dias atrás", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "hora", + "time_hours": "horas", + "time_day": "dia", + "time_days": "dias", + "time_week": "semana", + "time_weeks": "semanas", + "time_month": "mês", + "time_months": "meses", + "time_minutes": "minutos", + "time_allTime": "Todos os tempos", + "dialog_disconnect": "Desconectar", + "dialog_disconnectConfirm": "Tem certeza de que deseja desconectar deste dispositivo?", + "login_repeaterLogin": "Login ao Repetidor", + "login_roomLogin": "Login de Sala", + "login_password": "Senha", + "login_enterPassword": "Insira a senha", + "login_savePassword": "Salvar senha", + "login_savePasswordSubtitle": "A senha será armazenada com segurança neste dispositivo.", + "login_repeaterDescription": "Insira a senha do repetidor para acessar as configurações e o status.", + "login_roomDescription": "Insira a senha da sala para acessar as configurações e o status.", + "login_routing": "Rotas", + "login_routingMode": "Modo de roteamento", + "login_autoUseSavedPath": "Auto (usar caminho salvo)", + "login_forceFloodMode": "Modo de Inundação Forçado", + "login_managePaths": "Gerenciar Caminhos", + "login_login": "Login", + "login_attempt": "Tentar {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Login falhou: {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Recarregar", + "common_clear": "Limpar", + "path_currentPath": "Caminho atual: {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Usando {count} {count, plural, =1{hop} other{hops}} caminho", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Insira Caminho Personalizado", + "path_currentPathLabel": "Caminho atual", + "path_hexPrefixInstructions": "Insira os prefixos hexadecimais de 2 caracteres para cada salto, separados por vírgulas.", + "path_hexPrefixExample": "A1,F2,3C (cada nó usa o primeiro byte de sua chave pública)", + "path_labelHexPrefixes": "Prefixo Hexadecimal", + "path_helperMaxHops": "Máximo de 64 saltos. Cada prefixo tem 2 caracteres hexadecimais (1 byte)", + "path_selectFromContacts": "Ou selecione de contatos:", + "path_noRepeatersFound": "Não foram encontrados repetidores ou servidores de sala.", + "path_customPathsRequire": "Caminhos personalizados exigem saltos intermediários que podem transmitir mensagens.", + "path_invalidHexPrefixes": "Prefixos hexadecimais inválidos: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "Caminho muito longo. Máximo de 64 saltos permitidos.", + "path_setPath": "Definir Caminho", + "repeater_management": "Gerenciamento de Repetidor", + "repeater_managementTools": "Ferramentas de Gerenciamento", + "repeater_status": "Status", + "repeater_statusSubtitle": "Visualizar status do repetidor, estatísticas e vizinhos.", + "repeater_telemetry": "Telemetria", + "repeater_telemetrySubtitle": "Visualizar telemetria de sensores e estatísticas do sistema", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Enviar comandos ao repetidor", + "repeater_settings": "Configurações", + "repeater_settingsSubtitle": "Configurar parâmetros do repetidor", + "repeater_statusTitle": "Status do Repetidor", + "repeater_routingMode": "Modo de roteamento", + "repeater_autoUseSavedPath": "Auto (usar caminho salvo)", + "repeater_forceFloodMode": "Modo de Inundação Forçado", + "repeater_pathManagement": "Gerenciamento de caminhos", + "repeater_refresh": "Atualizar", + "repeater_statusRequestTimeout": "Solicitação de status expirou.", + "repeater_errorLoadingStatus": "Erro ao carregar o status: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Informações do Sistema", + "repeater_battery": "Bateria", + "repeater_clockAtLogin": "Relógio (no login)", + "repeater_uptime": "Disponibilidade", + "repeater_queueLength": "Comprimento da Fila", + "repeater_debugFlags": "Marcar Flags de Depuração", + "repeater_radioStatistics": "Estatísticas de Rádio", + "repeater_lastRssi": "Último RSSI", + "repeater_lastSnr": "Último SNR", + "repeater_noiseFloor": "Nível de Ruído", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Estatísticas de Pacote", + "repeater_sent": "Enviado", + "repeater_received": "Recebido", + "repeater_duplicates": "Duplicatas", + "repeater_daysHoursMinsSecs": "{days} dias {hours}h {minutes}m {seconds}s", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Total: {total}, Inundação: {flood}, Direto: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Total: {total}, Inundação: {flood}, Direto: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Inundação: {flood}, Direto: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Total: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Configurações do Repetidor", + "repeater_basicSettings": "Configurações Básicas", + "repeater_repeaterName": "Nome do Repetidor", + "repeater_repeaterNameHelper": "Exibir nome para este repetidor", + "repeater_adminPassword": "Senha de Administrador", + "repeater_adminPasswordHelper": "Acesso completo de senha", + "repeater_guestPassword": "Senha de convidado", + "repeater_guestPasswordHelper": "Acesso com senha de leitura somente", + "repeater_radioSettings": "Configurações de Rádio", + "repeater_frequencyMhz": "Frequência (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Power", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Largura de banda", + "repeater_spreadingFactor": "Fator de Dispersão", + "repeater_codingRate": "Taxa de Codificação", + "repeater_locationSettings": "Configurações de Localização", + "repeater_latitude": "Latitude", + "repeater_latitudeHelper": "Graus decimais (por exemplo, 37,7749)", + "repeater_longitude": "Longitude", + "repeater_longitudeHelper": "Graus decimais (por exemplo, -122,4194)", + "repeater_features": "Recursos", + "repeater_packetForwarding": "Encaminhamento de Pacotes", + "repeater_packetForwardingSubtitle": "Habilitar o repetidor para encaminhar pacotes", + "repeater_guestAccess": "Acesso de Convidado", + "repeater_guestAccessSubtitle": "Permitir acesso de convidado somente leitura", + "repeater_privacyMode": "Modo de Privacidade", + "repeater_privacyModeSubtitle": "Esconder nome/localização em anúncios", + "repeater_advertisementSettings": "Configurações de Anúncios", + "repeater_localAdvertInterval": "Intervalo de Anúncio Local", + "repeater_localAdvertIntervalMinutes": "{minutes} minutos", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Intervalo de Anúncio de Inundação", + "repeater_floodAdvertIntervalHours": "{hours} horas", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Intervalo de Anúncio Criptografado", + "repeater_dangerZone": "Zona de Perigo", + "repeater_rebootRepeater": "Reiniciar Repetidor", + "repeater_rebootRepeaterSubtitle": "Reiniciar o dispositivo repetidor", + "repeater_rebootRepeaterConfirm": "Tem certeza de que deseja reiniciar este repetidor?", + "repeater_regenerateIdentityKey": "Gerar Chave de Identidade", + "repeater_regenerateIdentityKeySubtitle": "Gerar nova chave pública/privada", + "repeater_regenerateIdentityKeyConfirm": "Isso gerará uma nova identidade para o repetidor. Continuar?", + "repeater_eraseFileSystem": "Excluir Sistema de Arquivos", + "repeater_eraseFileSystemSubtitle": "Formatar o sistema de arquivos do repetidor", + "repeater_eraseFileSystemConfirm": "AVISO: Isso apagará todos os dados no repetidor. Isso não pode ser desfeito!", + "repeater_eraseSerialOnly": "Apagar está disponível apenas via console serial.", + "repeater_commandSent": "Comando enviado: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Erro ao enviar comando: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "Confirmar", + "repeater_settingsSaved": "Configurações salvas com sucesso", + "repeater_errorSavingSettings": "Erro ao salvar as configurações: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Atualizar Configurações Básicas", + "repeater_refreshRadioSettings": "Atualizar Configurações de Rádio", + "repeater_refreshTxPower": "Atualizar TX de energia", + "repeater_refreshLocationSettings": "Atualizar Configurações de Localização", + "repeater_refreshPacketForwarding": "Atualizar Roteamento de Pacotes", + "repeater_refreshGuestAccess": "Atualizar Acesso de Convidados", + "repeater_refreshPrivacyMode": "Atualizar Modo Privacidade", + "repeater_refreshAdvertisementSettings": "Atualizar Configurações do Anúncio", + "repeater_refreshed": "{label} atualizado", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Erro ao atualizar {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Repetidor CLI", + "repeater_debugNextCommand": "Depurar Próximo Comando", + "repeater_commandHelp": "Ajuda", + "repeater_clearHistory": "Limpar Histórico", + "repeater_noCommandsSent": "Ainda não foram enviadas comandos.", + "repeater_typeCommandOrUseQuick": "Digite um comando abaixo ou use comandos rápidos", + "repeater_enterCommandHint": "Insira o comando...", + "repeater_previousCommand": "Comando anterior", + "repeater_nextCommand": "Próxima ação", + "repeater_enterCommandFirst": "Insira um comando primeiro", + "repeater_cliCommandFrameTitle": "Frame de Comando CLI", + "repeater_cliCommandError": "Erro: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Obter Nome", + "repeater_cliQuickGetRadio": "Obter Rádio", + "repeater_cliQuickGetTx": "Obter TX", + "repeater_cliQuickNeighbors": "Vizinhos", + "repeater_cliQuickVersion": "Versão", + "repeater_cliQuickAdvertise": "Anunciar", + "repeater_cliQuickClock": "Relógio", + "repeater_cliHelpAdvert": "Envia um pacote de anúncios", + "repeater_cliHelpReboot": "Reinicia o dispositivo. (note, você pode obter 'Timeout' que é normal)", + "repeater_cliHelpClock": "Exibe a hora atual de cada dispositivo, de acordo com o relógio do dispositivo.", + "repeater_cliHelpPassword": "Define uma nova senha de administrador para o dispositivo.", + "repeater_cliHelpVersion": "Mostra a versão do dispositivo e a data de construção do firmware.", + "repeater_cliHelpClearStats": "Reseta vários contadores de estatísticas para zero.", + "repeater_cliHelpSetAf": "Define o fator de tempo de ar.", + "repeater_cliHelpSetTx": "Define a potência de transmissão LoRa em dBm (redefinir para aplicar).", + "repeater_cliHelpSetRepeat": "Habilita ou desabilita o papel do repetidor para este nó.", + "repeater_cliHelpSetAllowReadOnly": "(Servidor de sala) Se 'ligado', então o login com senha em branco será permitido, mas não poderá Postar na sala. (apenas ler).", + "repeater_cliHelpSetFloodMax": "Define o número máximo de saltos de pacotes de inundação de entrada (se for >= máximo, o pacote não é encaminhado)", + "repeater_cliHelpSetIntThresh": "Define o Limite de Interferência (em dB). O valor padrão é 14. Defina como 0 para desativar a detecção de interferência de canal.", + "repeater_cliHelpSetAgcResetInterval": "Define o intervalo para resetar o Controlador de Ganho Automático. Defina como 0 para desativar.", + "repeater_cliHelpSetMultiAcks": "Habilita ou desabilita a funcionalidade de \"double ACKs\".", + "repeater_cliHelpSetAdvertInterval": "Define o intervalo do timer em minutos para enviar um pacote de anúncio local (sem salto). Defina como 0 para desativar.", + "repeater_cliHelpSetFloodAdvertInterval": "Define o intervalo do timer em horas para enviar um pacote de anúncio em massa. Defina como 0 para desativar.", + "repeater_cliHelpSetGuestPassword": "Define/atualiza a senha do convidado. (para repetidores, os logins de convidados podem enviar a solicitação \"Obter Estatísticas\")", + "repeater_cliHelpSetName": "Define o nome do anúncio.", + "repeater_cliHelpSetLat": "Define a latitude do mapa de anúncios. (graus decimais)", + "repeater_cliHelpSetLon": "Define a longitude do mapa de anúncios. (graus decimais)", + "repeater_cliHelpSetRadio": "Define completamente novos parâmetros de rádio e salva nas preferências. Requer um comando \"reboot\" para aplicar.", + "repeater_cliHelpSetRxDelay": "Configurações (experimental) base (deve ser > 1 para efeito) para aplicar um pequeno atraso aos pacotes recebidos, com base na força do sinal/pontuação. Defina como 0 para desativar.", + "repeater_cliHelpSetTxDelay": "Define um fator multiplicado com o tempo-em-ar para um pacote de modo de inundação e com um sistema de slot aleatório, para atrasar seu encaminhamento. (para diminuir a probabilidade de colisões)", + "repeater_cliHelpSetDirectTxDelay": "Igual a txdelay, mas para aplicar um atraso aleatório à encaminhamento de pacotes em modo direto.", + "repeater_cliHelpSetBridgeEnabled": "Ativar/Desativar ponte.", + "repeater_cliHelpSetBridgeDelay": "Definir atraso antes de retransmitir pacotes.", + "repeater_cliHelpSetBridgeSource": "Escolha se a ponte retransmitirá pacotes recebidos ou pacotes transmitidos.", + "repeater_cliHelpSetBridgeBaud": "Definir a taxa de baud para as pontes rs232.", + "repeater_cliHelpSetBridgeSecret": "Definir segredo de ponte para pontes espnow.", + "repeater_cliHelpSetAdcMultiplier": "Define um fator personalizado para ajustar a voltagem de bateria relatada (apenas suportado em placas selecionadas).", + "repeater_cliHelpTempRadio": "Define parâmetros de rádio temporários para o número especificado de minutos, revertendo para os parâmetros de rádio originais posteriormente. (não salva nas preferências).", + "repeater_cliHelpSetPerm": "Modifica o ACL. Remove a entrada correspondente (pelo prefixo de pubkey) se \"permissions\" for zero. Adiciona uma nova entrada se o pubkey-hex for de comprimento total e não estiver atualmente no ACL. Atualiza a entrada por correspondência de prefixo de pubkey. Os bits de permissão variam conforme o papel do firmware, mas os 2 bits inferiores são: 0 (Guest), 1 (Read only), 2 (Read write), 3 (Admin)", + "repeater_cliHelpGetBridgeType": "Obtém tipo de ponte nenhum, rs232, espnow", + "repeater_cliHelpLogStart": "Inicia o registro de pacotes no sistema de arquivos.", + "repeater_cliHelpLogStop": "Para interromper o registro de pacotes no sistema de arquivos.", + "repeater_cliHelpLogErase": "Apaga os logs do pacote do sistema de arquivos.", + "repeater_cliHelpNeighbors": "Mostra uma lista de outros nós de repetição ouvidos através de anúncios zero-hop. Cada linha é id-prefixo-hexadecimal:timestamp:snr-vezes-4", + "repeater_cliHelpNeighborRemove": "Remove a primeira entrada correspondente (por prefixo de chave pública (hexadecimal)) da lista de vizinhos.", + "repeater_cliHelpRegion": "(série apenas) Lista todas as regiões definidas e as permissões de inundação atuais.", + "repeater_cliHelpRegionLoad": "NOTA: isto é uma invocação multi-comando especial. Cada comando subsequente é um nome de região (indentado com espaços para indicar a hierarquia pai, com um espaço mínimo). Terminado enviando uma linha em branco/comando.", + "repeater_cliHelpRegionGet": "Procura região com o prefixo de nome dado (ou \"\\\" para o âmbito global). Responde com \"-> nome-região (nome-pai) 'F'\"", + "repeater_cliHelpRegionPut": "Adiciona ou atualiza uma definição de região com o nome fornecido.", + "repeater_cliHelpRegionRemove": "Remove uma definição de região com o nome fornecido. (deve corresponder exatamente e não ter regiões filhas)", + "repeater_cliHelpRegionAllowf": "Define a permissão de 'F'luido para a região especificada. ('' para o escopo global/legado)", + "repeater_cliHelpRegionDenyf": "Remove a permissão de \"F\"luido para a região especificada. (NOTA: neste momento NÃO é aconselhável usar isso no escopo global/legado!!)", + "repeater_cliHelpRegionHome": "Responde com a região 'home' atual. (Observação aplicada em nenhum lugar ainda, reservado para o futuro)", + "repeater_cliHelpRegionHomeSet": "Define a região 'casa'.", + "repeater_cliHelpRegionSave": "Persiste a lista/mapa de regiões para o armazenamento.", + "repeater_cliHelpGps": "Mostra o status do GPS. Quando o GPS estiver desligado, responde apenas com \"off\", se estiver ligado, responde com \"on\", status, fix, contagem de satélites.", + "repeater_cliHelpGpsOnOff": "Alterna o estado de energia do GPS.", + "repeater_cliHelpGpsSync": "Sincroniza o tempo do nó com o relógio GPS.", + "repeater_cliHelpGpsSetLoc": "Define a posição do nó para coordenadas GPS e salvar preferências.", + "repeater_cliHelpGpsAdvert": "Define a configuração de anúncio da localização do nó:\n- nenhum: não incluir a localização nos anúncios\n- compartilhar: compartilhar a localização GPS (do SensorManager)\n- preferências: anunciar a localização armazenada nas preferências", + "repeater_cliHelpGpsAdvertSet": "Define a configuração do anúncio de localização.", + "repeater_commandsListTitle": "Lista de Comandos", + "repeater_commandsListNote": "NOTA: para os diversos comandos \"set...\", também existe um comando \"get...\".", + "repeater_general": "Geral", + "repeater_settingsCategory": "Configurações", + "repeater_bridge": "Ponte", + "repeater_logging": "Registrar", + "repeater_neighborsRepeaterOnly": "Vizinhos (apenas repetidor)", + "repeater_regionManagementRepeaterOnly": "Gerenciamento de Região (Apenas Repetidor)", + "repeater_regionNote": "Os comandos de região foram introduzidos para gerenciar definições e permissões de região.", + "repeater_gpsManagement": "Gerenciamento GPS", + "repeater_gpsNote": "O comando GPS foi introduzido para gerenciar tópicos relacionados à localização.", + "telemetry_receivedData": "Dados de Telemetria Recebidos", + "telemetry_requestTimeout": "Solicitação de telemetria expirou o tempo.", + "telemetry_errorLoading": "Erro ao carregar a telemetria: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "Não estão disponíveis dados de telemetria.", + "telemetry_channelTitle": "Canal {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Bateria", + "telemetry_voltageLabel": "Tensão", + "telemetry_mcuTemperatureLabel": "Temperatura do MCU", + "telemetry_temperatureLabel": "Temperatura", + "telemetry_currentLabel": "Atual", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Rótulo de Caminho de Pacote", + "channelPath_viewMap": "Ver mapa", + "channelPath_otherObservedPaths": "Outros Caminhos Observados", + "channelPath_repeaterHops": "Saltos do Repetidor", + "channelPath_noHopDetails": "Os detalhes do pacote não estão disponíveis.", + "channelPath_messageDetails": "Detalhes da Mensagem", + "channelPath_senderLabel": "Remetente", + "channelPath_timeLabel": "Tempo", + "channelPath_repeatsLabel": "Repete", + "channelPath_pathLabel": "Caminho {index}", + "channelPath_observedLabel": "Observado", + "channelPath_observedPathTitle": "Rastreamento observado {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "Não há dados de localização.", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Desconhecido", + "channelPath_floodPath": "Inundação", + "channelPath_directPath": "Salvar", + "channelPath_observedZeroOf": "0 de {total} saltos", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} de {total} saltos", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Mapa de Caminhos", + "channelPath_noRepeaterLocations": "Não estão disponíveis localizações de repetidores para este caminho.", + "channelPath_primaryPath": "Caminho {index} (Primário)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Caminho", + "channelPath_observedPathHeader": "Rastreamento Observado", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "Não estão disponíveis detalhes de voo para este pacote.", + "channelPath_unknownRepeater": "Repetidor Desconhecido", + "listFilter_tooltip": "Filtrar e ordenar", + "listFilter_sortBy": "Ordenar por", + "listFilter_latestMessages": "Últimas mensagens", + "listFilter_heardRecently": "Ouvido recentemente", + "listFilter_az": "A-Z", + "listFilter_filters": "Filtros", + "listFilter_all": "Tudo", + "listFilter_users": "Usuários", + "listFilter_repeaters": "Repetidores", + "listFilter_roomServers": "Servidores de sala", + "listFilter_unreadOnly": "Apenas não lido", + "listFilter_newGroup": "Novo grupo" +} diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb new file mode 100644 index 0000000..67043a7 --- /dev/null +++ b/lib/l10n/app_sk.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "sk", + "appTitle": "MeshCore Open", + "nav_contacts": "Kontakty", + "nav_channels": "Kanály", + "nav_map": "Mapa", + "common_cancel": "Zrušiť", + "common_connect": "Pripojiť", + "common_unknownDevice": "Neznáme zariadenie", + "common_save": "Uložiť", + "common_delete": "Odstrániť", + "common_close": "Zavrieť", + "common_edit": "Upraviť", + "common_add": "Pridať", + "common_settings": "Nastavenia", + "common_disconnect": "Odpojiť", + "common_connected": "Pripojené", + "common_disconnected": "Odpojené", + "common_create": "Vytvoriť", + "common_continue": "Pokračovať", + "common_share": "Zdieľať", + "common_copy": "Kopírovať", + "common_retry": "Pokusť znova", + "common_hide": "Skryť", + "common_remove": "Odstrániť", + "common_enable": "Povolit", + "common_disable": "Zakázať", + "common_reboot": "Restartovať", + "common_loading": "Načítavanie...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Skrívania zariadení...", + "scanner_connecting": "Pripojujem sa...", + "scanner_disconnecting": "Odpojuje sa...", + "scanner_notConnected": "Nezriadené", + "scanner_connectedTo": "Pripojené k {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Hľadám zariadenia MeshCore...", + "scanner_tapToScan": "Stlač skenovanie na nájdenie zariadení MeshCore.", + "scanner_connectionFailed": "Pripojenie zlyhalo: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Zastavte", + "scanner_scan": "Skončiť", + "device_quickSwitch": "Rýchle prepínač", + "device_meshcore": "MeshCore", + "settings_title": "Nastavenia", + "settings_deviceInfo": "Informácie o zariadení", + "settings_appSettings": "Nastavenia aplikácie", + "settings_appSettingsSubtitle": "Upozornenia, správy a nastavenia mapy", + "settings_nodeSettings": "Nastavenia uzla", + "settings_nodeName": "Názov uzla", + "settings_nodeNameNotSet": "Nezriadené", + "settings_nodeNameHint": "Zadajte názov uzla", + "settings_nodeNameUpdated": "Meno aktualizované", + "settings_radioSettings": "Nastavenia rádia", + "settings_radioSettingsSubtitle": "Frekvencia, výkon, rozptylovací faktor", + "settings_radioSettingsUpdated": "Nastavenia rádia aktualizované", + "settings_location": "Lokalita", + "settings_locationSubtitle": "GPS súradnice", + "settings_locationUpdated": "Lokalita aktualizovaná", + "settings_locationBothRequired": "Zadajte obidve zložky zemyslenia a zložky meracieho kruhu.", + "settings_locationInvalid": "Neplatná šírka alebo dĺžka.", + "settings_latitude": "Súradnica", + "settings_longitude": "Dĺžka", + "settings_privacyMode": "Režim ochrany súkromia", + "settings_privacyModeSubtitle": "Skryť meno/poloha v reklamách", + "settings_privacyModeToggle": "Prepínač súkromného režimu skryje vaše meno a polohu v reklamách.", + "settings_privacyModeEnabled": "Ochranný režim je povolený.", + "settings_privacyModeDisabled": "Ochranný režim je vypnutý", + "settings_actions": "Možné akcie", + "settings_sendAdvertisement": "Odoslať reklamu", + "settings_sendAdvertisementSubtitle": "Momentálne priezornejšie.", + "settings_advertisementSent": "Reklama odeslaná", + "settings_syncTime": "Čas synchronizácie", + "settings_syncTimeSubtitle": "Nastaviť hodiny zariadenia na čas telefónu", + "settings_timeSynchronized": "Čas synchronizovaný", + "settings_refreshContacts": "Načítať Kontakty", + "settings_refreshContactsSubtitle": "Načítať zoznam kontaktov z zariadenia", + "settings_rebootDevice": "Restartovať zariadenie", + "settings_rebootDeviceSubtitle": "Restartujte zariadenie MeshCore.", + "settings_rebootDeviceConfirm": "Ste si istý, že chcete zariadenie reštartovať? Budete odpojení.", + "settings_debug": "Ladenie", + "settings_bleDebugLog": "Log BLE Debug", + "settings_bleDebugLogSubtitle": "Príkazy BLE, odpovede a surové dáta", + "settings_appDebugLog": "Záznam ladenia aplikácie", + "settings_appDebugLogSubtitle": "Správy z ladenia aplikácie", + "settings_about": "O nás", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "MeshCore Open Source Projekt 2024", + "settings_aboutDescription": "Otvorený zdrojový Flutter klient pre MeshCore LoRa sieťové zariadenia.", + "settings_infoName": "Meno", + "settings_infoId": "ID", + "settings_infoStatus": "Status", + "settings_infoBattery": "Batéria", + "settings_infoPublicKey": "Verejný kľúč", + "settings_infoContactsCount": "Počet kontaktov", + "settings_infoChannelCount": "Počet kanálov", + "settings_presets": "Prednastavenia", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Frekvencia (MHz)", + "settings_frequencyHelper": "300,0 – 2500,0", + "settings_frequencyInvalid": "Neplatná frekvencia (300-2500 MHz)", + "settings_bandwidth": "Šírka pásma", + "settings_spreadingFactor": "Rozptýľovací faktor", + "settings_codingRate": "Cenový kurz pre programovanie", + "settings_txPower": "TX Výkon (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Neplatná hodnota výkonu TX (0-22 dBm)", + "settings_longRange": "Dlhý dosah", + "settings_fastSpeed": "Rýchla rýchlosť", + "settings_error": "Chyba: {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "Nastavenia aplikácie", + "appSettings_appearance": "Vzhľad", + "appSettings_theme": "Téma", + "appSettings_themeSystem": "Predvolený systém", + "appSettings_themeLight": "Svetlo", + "appSettings_themeDark": "Tmavé", + "appSettings_language": "Jazyk", + "appSettings_languageSystem": "Predvolený systém", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Upozornenia", + "appSettings_enableNotifications": "Povolte Notifikácie", + "appSettings_enableNotificationsSubtitle": "Zísť o upozornenia na správy a inzeráty", + "appSettings_notificationPermissionDenied": "Odmietená povolenie notifikácií", + "appSettings_notificationsEnabled": "Upozornenia povolené", + "appSettings_notificationsDisabled": "Upozornenia sú vypnuté", + "appSettings_messageNotifications": "Správy od upozornení", + "appSettings_messageNotificationsSubtitle": "Zobraziť upozornenie pri prijímaní nových správ", + "appSettings_channelMessageNotifications": "Notifikácie z kanálov", + "appSettings_channelMessageNotificationsSubtitle": "Zobraziť upozornenie pri prijímaní správ z kanálu", + "appSettings_advertisementNotifications": "Upozornenia na reklamy", + "appSettings_advertisementNotificationsSubtitle": "Zobraziť upozornenie, keď sa objavia nové uzly.", + "appSettings_messaging": "Správy", + "appSettings_clearPathOnMaxRetry": "Vyčisti cestu na Max Retry", + "appSettings_clearPathOnMaxRetrySubtitle": "Resetovať kontaktný priebeh po 5 neúspešných pokusoch o doručenie", + "appSettings_pathsWillBeCleared": "Cesty budú vymazané po 5 neúspešných pokusoch.", + "appSettings_pathsWillNotBeCleared": "Cesty sa automaticky nevymazávajú.", + "appSettings_autoRouteRotation": "Automatické prechodové trasy", + "appSettings_autoRouteRotationSubtitle": "Striedajte sa medzi najlepšími trasami a režimom povodňovej analýzy.", + "appSettings_autoRouteRotationEnabled": "Automatické otáčanie trasy povolené", + "appSettings_autoRouteRotationDisabled": "Automatické prekladanie trás pozastavené", + "appSettings_battery": "Batéria", + "appSettings_batteryChemistry": "Chemická zloženie batérie", + "appSettings_batteryChemistryPerDevice": "Nastavenie pre {deviceName}", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Pripojte sa k zariadeniu na výber", + "appSettings_batteryNmc": "18650 NMC (3,0-4,2V)", + "appSettings_batteryLifepo4": "LiFePO4 (2,6–3,65V)", + "appSettings_batteryLipo": "LiPo (3,0-4,2V)", + "appSettings_mapDisplay": "Zobrazenie mapy", + "appSettings_showRepeaters": "Zobraziť opakovače", + "appSettings_showRepeatersSubtitle": "Zobraziť opakujúce sa uzly na mape", + "appSettings_showChatNodes": "Zobraziť uzly chatových správ", + "appSettings_showChatNodesSubtitle": "Zobraziť chatové uzly na mape", + "appSettings_showOtherNodes": "Zobraziť ďalšie uzly", + "appSettings_showOtherNodesSubtitle": "Zobraziť ostatné typy uzlov na mape", + "appSettings_timeFilter": "Filtrovacie Časové Obdoby", + "appSettings_timeFilterShowAll": "Zobraziť všetky uzly", + "appSettings_timeFilterShowLast": "Zobraziť uzly z posledných {hours} hodín", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Filtračný čas mapy", + "appSettings_showNodesDiscoveredWithin": "Zobraziť uzly objavené v:", + "appSettings_allTime": "Všetky časy", + "appSettings_lastHour": "Posledná hodina", + "appSettings_last6Hours": "Posledné 6 hodín", + "appSettings_last24Hours": "Posledných 24 hodín", + "appSettings_lastWeek": "Minul týždeň", + "appSettings_offlineMapCache": "Offline Mapa Pamäť", + "appSettings_noAreaSelected": "Neoznačila sa žiadna oblasť", + "appSettings_areaSelectedZoom": "Vyberená oblasť (zoom {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Ladenie", + "appSettings_appDebugLogging": "Záznamy ladenia aplikácie", + "appSettings_appDebugLoggingSubtitle": "Logovací správy aplikácie pre ladenie", + "appSettings_appDebugLoggingEnabled": "Aplikácia povolila ladenie protokolmi", + "appSettings_appDebugLoggingDisabled": "Zabudované ladenie aplikácie je vypnuté.", + "contacts_title": "Kontakty", + "contacts_noContacts": "Zatiaľ žiadne kontakty.", + "contacts_contactsWillAppear": "Kontakty sa zobrazia, keď zariadenia spúšťajú reklamu.", + "contacts_searchContacts": "Vyhľadávajte kontakty...", + "contacts_noUnreadContacts": "Žiadne neprečítané kontakty", + "contacts_noContactsFound": "Neboli nájdených žiadnych kontaktov ani skupiny.", + "contacts_deleteContact": "Odstrániť kontakt", + "contacts_removeConfirm": "Odstrániť {contactName} z kontaktov?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Spravovať opakované zoznamy", + "contacts_roomLogin": "Prihlásenie do miestnosti", + "contacts_openChat": "Otvorené Chat", + "contacts_editGroup": "Upraviť skupinu", + "contacts_deleteGroup": "Vymažť skupinu", + "contacts_deleteGroupConfirm": "Odstrániť \"{groupName}\"?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Nová skupina", + "contacts_groupName": "Názov skupiny", + "contacts_groupNameRequired": "Skupina musí mať názov.", + "contacts_groupAlreadyExists": "Skupina \"{name}\" už existuje", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Filtrovať kontakty...", + "contacts_noContactsMatchFilter": "Žiadne kontakty neodídu vášmu filtru.", + "contacts_noMembers": "Žiadni členovia", + "contacts_lastSeenNow": "Posledné zreteľné zobrazenie teraz", + "contacts_lastSeenMinsAgo": "Posledné zobrazenie {minutes} min. dozadu", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Zobral/Zabral poslednýkrát pred hodinou.", + "contacts_lastSeenHoursAgo": "Posledné zobrazenie {hours} hodín dozadu", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Zobral/Zabral posledný raz pred 1 dňom.", + "contacts_lastSeenDaysAgo": "Posledné zobrazenie {days} dní dozadu", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Kanály", + "channels_noChannelsConfigured": "Neobsiahnuté žiadne kanály", + "channels_addPublicChannel": "Pridať verejný kanál", + "channels_searchChannels": "Vyhľadávajte kanály...", + "channels_noChannelsFound": "Neobsiahlo sa žiadnych kanálov.", + "channels_channelIndex": "Kanál {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Kanál s hashtagom", + "channels_public": "Veľké verejné", + "channels_private": "Osobné", + "channels_publicChannel": "Veľké verejne kanály", + "channels_privateChannel": "Osobné kanál", + "channels_editChannel": "Upraviť kanál", + "channels_deleteChannel": "Odstrániť kanál", + "channels_deleteChannelConfirm": "Odstrániť \"{name}\"? To sa nedá zrušiť.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Kanál \"{name}\" bol odstránený", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Pridať kanál", + "channels_channelIndexLabel": "Index kanála", + "channels_channelName": "Názov kanálu", + "channels_usePublicChannel": "Použite verejný kanál", + "channels_standardPublicPsk": "Štandardný verejný PSK", + "channels_pskHex": "PSK (Šifrovacia kľúčik)", + "channels_generateRandomPsk": "Generovať náhodný PSK", + "channels_enterChannelName": "Prosím, zadajte názov kanála.", + "channels_pskMustBe32Hex": "PSK musí mať 32 hexadecimálových znakov.", + "channels_channelAdded": "Kanál \"{name}\" pridaný", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Upraviť kanál {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "Odstránenie kompresie SMAZ", + "channels_channelUpdated": "Kanál \"{name}\" bol aktualizovaný", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "Veľký kanál pridaný", + "channels_sortBy": "Triediť podľa", + "channels_sortManual": "Ručne", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "Posledné správy", + "channels_sortUnread": "Nezriadené", + "chat_noMessages": "Zatiaľ žiadne správy.", + "chat_sendMessageToStart": "Pošlite správu na začiatok", + "chat_originalMessageNotFound": "Neznámy pôvodný odkaz.", + "chat_replyingTo": "Odpovedám {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Odpovedať {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Lokalita", + "chat_sendMessageTo": "Pošli správu {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Napište správu...", + "chat_messageTooLong": "Správa je príliš dlhá (max {maxBytes} bytov).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Správa skopírovaná", + "chat_messageDeleted": "Posolstvo odstránené", + "chat_retryingMessage": "Pokus o obnovenie", + "chat_retryCount": "Skúsiť {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "Odoslať GIF", + "chat_reply": "Odpovedať", + "chat_addReaction": "Pridať Reakciu", + "chat_me": "Mne", + "emojiCategorySmileys": "Emoji", + "emojiCategoryGestures": "Gestá", + "emojiCategoryHearts": "Srdcia", + "emojiCategoryObjects": "Objekty", + "gifPicker_title": "Vyberte GIF", + "gifPicker_searchHint": "Vyhľadávajte GIFy...", + "gifPicker_poweredBy": "Napájané spoločnosťou GIPHY", + "gifPicker_noGifsFound": "Neboli nájdené žiadne GIFy.", + "gifPicker_failedLoad": "Nepodarilo sa načítať GIFy", + "gifPicker_failedSearch": "Nepodarilo sa vyhľadať GIFy", + "gifPicker_noInternet": "Žiadna internetová konektivita", + "debugLog_appTitle": "Záznam ladenia aplikácie", + "debugLog_bleTitle": "Log BLE Debug", + "debugLog_copyLog": "Kopírovať záznam", + "debugLog_clearLog": "Vymažať záznam", + "debugLog_copied": "Záznam ladenia skopírovaný", + "debugLog_bleCopied": "Kopírovaný záznam z BLE.", + "debugLog_noEntries": "Zatiaľ neboli zaznamenané žiadne debug logy.", + "debugLog_enableInSettings": "Povolte ladicové logy v nastaveniach", + "debugLog_frames": "Rámce", + "debugLog_rawLogRx": "Raw Log-RX", + "debugLog_noBleActivity": "Zatiaľ žiadna aktivita BLE.", + "debugFrame_length": "Dĺžka rámca: {count} bajtov", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Prikáž: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Textová zvesť:", + "debugFrame_destinationPubKey": "- Cieľový PubKey: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Časové označenie: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Žiadne vlajky: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- Typ textu: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Jednoduché", + "debugFrame_text": "- Text: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Hex Dump:", + "chat_pathManagement": "Správa ciest", + "chat_routingMode": "Režim trasy", + "chat_autoUseSavedPath": "Použiť uloženú cestu", + "chat_forceFloodMode": "Zavrieť režim núdzového povodňového režimu", + "chat_recentAckPaths": "Nedávne cesty ACK (klepni na použitie):", + "chat_pathHistoryFull": "História ciest je plná. Odstráňte záznamy, aby ste mohli pridať nové.", + "chat_hopSingular": "Skok", + "chat_hopPlural": "Skákať", + "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "Úspechy", + "chat_removePath": "Odstrániť cestu", + "chat_noPathHistoryYet": "Zatiaľ žiadna história trás.\nPošlite správu a objavte trasy.", + "chat_pathActions": "Cesty:", + "chat_setCustomPath": "Nastaviť vlastnú cestu", + "chat_setCustomPathSubtitle": "Ručne zadajte trasu.", + "chat_clearPath": "Vyčistiš cestu", + "chat_clearPathSubtitle": "Znovu nájsť vynútene pri nasledujacej pošlite", + "chat_pathCleared": "Cesta vyčistená. Nasledujúce prepočetné získa trasu znova.", + "chat_floodModeSubtitle": "Použite prepínanie trasy v navigačnom paneli.", + "chat_floodModeEnabled": "Odosporňovacia prevádzka je zapnutá. Vypnite ju znova cez ikonu routovania v navigačnom páse.", + "chat_fullPath": "Celá cesta", + "chat_pathDetailsNotAvailable": "Podrobnosti o ceste zatiaľ dostupné nie sú. Skúste poslať správu na obnovenie.", + "chat_pathSetHops": "Cesta nastavená: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Uložené lokálne. Spojte sa na synchronizáciu.", + "chat_pathDeviceConfirmed": "Zariadenie potvrdené.", + "chat_pathDeviceNotConfirmed": "Zariadenie zatiaľ nebolo potvrdené.", + "chat_type": "Napište", + "chat_path": "Cesta", + "chat_publicKey": "Verejný kľúč", + "chat_compressOutgoingMessages": "Komprimovať odoslané správy", + "chat_floodForced": "Povodňová (nutená)", + "chat_directForced": "Priame (donútené)", + "chat_hopsForced": "{count} skokov (nutené)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Povod (automaticky)", + "chat_direct": "Priamo", + "chat_poiShared": "Zdieľané body záujmu", + "chat_unread": "Nezriadené: {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Mapa uzlov", + "map_noNodesWithLocation": "Žiadne uzly s údajmi o polohe", + "map_nodesNeedGps": "Uholníky musia zdieľať svoje GPS súradnice, aby sa zobrazili na mape.", + "map_nodesCount": "Uzly: {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Krúžky: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Rozhovor", + "map_repeater": "Opakovanie", + "map_room": "Izba", + "map_sensor": "Senzor", + "map_pinDm": "Zabudka (DM)", + "map_pinPrivate": "Zabudka (Osobná)", + "map_pinPublic": "Zablokovať (verejne)", + "map_lastSeen": "Posledné zreteľné zobrazenie", + "map_disconnectConfirm": "Ste si istý/á, že chcete odpojiť od tohto zariadenia?", + "map_from": "Od", + "map_source": "Zdroj", + "map_flags": "Zástavy", + "map_shareMarkerHere": "Zdieľte značku tu", + "map_pinLabel": "Označka upozornenia", + "map_label": "Značka", + "map_pointOfInterest": "Bod záujmu", + "map_sendToContact": "Pošleť na kontakt", + "map_sendToChannel": "Poslať do kanálu", + "map_noChannelsAvailable": "Неexistujú žiadne kanály.", + "map_publicLocationShare": "Zdieľiť verejnú lokalitu", + "map_publicLocationShareConfirm": "Čoskoro budete zdieľať polohu v {channelLabel}. Tento kanál je verejný a môže ho vidieť každý s PSK.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Pripojte sa k zariadeniu na zdieľanie značiek", + "map_filterNodes": "Filtrovať uzly", + "map_nodeTypes": "Typy uzlov", + "map_chatNodes": "Chatové uzly", + "map_repeaters": "Opakovadlá", + "map_otherNodes": "Ostatné uzly", + "map_keyPrefix": "Päťciferné predpona", + "map_filterByKeyPrefix": "Filtrovať podľa predponového kľúča", + "map_publicKeyPrefix": "Prefix verejného kľúča", + "map_markers": "Označkovače", + "map_showSharedMarkers": "Zobraziť zdieľané značky", + "map_lastSeenTime": "Posledný čas sledovania", + "map_sharedPin": "Zdieľaný PIN", + "map_joinRoom": "Pripojiť miestnosť", + "map_manageRepeater": "Spravovať Opakovanie", + "mapCache_title": "Offline Mapa Pamäť", + "mapCache_selectAreaFirst": "Vyberte si oblasť na predprerúčenie.", + "mapCache_noTilesToDownload": "Žiadne dlaždice na stiahnutie pre toto zóna", + "mapCache_downloadTilesTitle": "Stiahnuť dlaždice", + "mapCache_downloadTilesPrompt": "Stiahnuť {count} dlaždíc na offline použitie?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Stiahnuť", + "mapCache_cachedTiles": "Zabudené {count} dlaždíc", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Uložené {downloaded} dlaždice ({failed} neúspešné)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Vymazať offline uloženie", + "mapCache_clearOfflineCachePrompt": "Odstrániť všetky uložené mapové dlaždice?", + "mapCache_offlineCacheCleared": "Offline polia vymazaná", + "mapCache_noAreaSelected": "Neoznačila sa žiadna oblasť", + "mapCache_cacheArea": "Obdĺžková oblasť", + "mapCache_useCurrentView": "Použite aktuálny zobrazenie", + "mapCache_zoomRange": "Rozsah zväčšenia", + "mapCache_estimatedTiles": "Odhadnuté dlaždice: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Stiahnuté {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Stiahnuť dlaždice", + "mapCache_clearCacheButton": "Vyprázdniť Vädsť", + "mapCache_failedDownloads": "Neúspešné stiahnutia: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Príbeh", + "time_minutesAgo": "{minutes} min dozadu", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours} h dozadu", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} dní dozadu", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "hodina", + "time_hours": "hodiny", + "time_day": "deň", + "time_days": "dni", + "time_week": "týždeň", + "time_weeks": "týždne", + "time_month": "mesiac", + "time_months": "mesiace", + "time_minutes": "minúty", + "time_allTime": "Všetko Časom", + "dialog_disconnect": "Odpojiť", + "dialog_disconnectConfirm": "Ste si istý/á, že chcete odpojiť od tohto zariadenia?", + "login_repeaterLogin": "Opätovné prihlásenie", + "login_roomLogin": "Prihlásenie do miestnosti", + "login_password": "Heslo", + "login_enterPassword": "Zadajte heslo", + "login_savePassword": "Uložiť heslo", + "login_savePasswordSubtitle": "Heslo bude bezpečne uložené na tomto zariadení.", + "login_repeaterDescription": "Zadajte heslo opakovača, aby ste získali prístup k nastaveniam a stavu.", + "login_roomDescription": "Zadajte heslo do miestnosti na prístup k nastaveniam a stavu.", + "login_routing": "Rútiace", + "login_routingMode": "Režim trasy", + "login_autoUseSavedPath": "Použiť uloženú cestu", + "login_forceFloodMode": "Zavrieť režim núdzového povodňového režimu", + "login_managePaths": "Spravovať Cesty", + "login_login": "Prihlásiť", + "login_attempt": "Skúšaj {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Prihlásenie zlyhalo: {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Načítať", + "common_clear": "Zmazať", + "path_currentPath": "Aktívna cesta: {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Používa {count} {count, plural, =1{hop} other{hops}} cestu", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Zadajte vlastný priebeh", + "path_currentPathLabel": "Aktuálny priebeh", + "path_hexPrefixInstructions": "Zadajte 2-miestne hexové predpony pre každú fázu, oddelené čiarkami.", + "path_hexPrefixExample": "A1,F2,3C (každý uzel používa prvý bajt svojho verejného kľúča)", + "path_labelHexPrefixes": "Cesty (hexové predpony)", + "path_helperMaxHops": "Max 64 skokov. Každý prefix je 2 hexadecimálne znaky (1 bajt).", + "path_selectFromContacts": "Vyberte sa z kontaktov:", + "path_noRepeatersFound": "Nenašli sa žiadne opakovače ani serverové miestnosti.", + "path_customPathsRequire": "Vlastné cesty vyžadujú medziletoch, ktoré môžu prenášať správky.", + "path_invalidHexPrefixes": "Neplatné hexové predpony: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "Cesta je príliš dlhá. Umožnené je maximum 64 skokov.", + "path_setPath": "Nastaviť cestu", + "repeater_management": "Správa opakérov", + "repeater_managementTools": "Nástroje na správu", + "repeater_status": "Status", + "repeater_statusSubtitle": "Zobraziť stav, štatistiky a susedov repeatera", + "repeater_telemetry": "Telemetria", + "repeater_telemetrySubtitle": "Zobraziť telemetriu senzorov a systémových štatistík", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Pošlite príkazy opakovaču", + "repeater_settings": "Nastavenia", + "repeater_settingsSubtitle": "Konfigurujte parametre opakovača", + "repeater_statusTitle": "Status opakého zboru", + "repeater_routingMode": "Režim trasy", + "repeater_autoUseSavedPath": "Použiť uloženú cestu", + "repeater_forceFloodMode": "Zavrieť režim núdzového povodňového režimu", + "repeater_pathManagement": "Správa trás", + "repeater_refresh": "Obnoviť", + "repeater_statusRequestTimeout": "Požiadavka stavu zlyhala.", + "repeater_errorLoadingStatus": "Chyba pri načítaní stavu: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Informácie o systéme", + "repeater_battery": "Batéria", + "repeater_clockAtLogin": "Čas (při přihlášení)", + "repeater_uptime": "Dostupnosť", + "repeater_queueLength": "Dĺžka fronty", + "repeater_debugFlags": "Kontrolné značky", + "repeater_radioStatistics": "Rádio Štatistiky", + "repeater_lastRssi": "Posledná RSSI", + "repeater_lastSnr": "Posledný SNR", + "repeater_noiseFloor": "Hladina šumu", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Statistiky balíka", + "repeater_sent": "Odoslané", + "repeater_received": "Prišlo", + "repeater_duplicates": "Duplikáty", + "repeater_daysHoursMinsSecs": "{days} dní {hours}h {minutes}m {seconds}s", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Celkem: {total}, Povodňový režim: {flood}, Priamy: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Celkem: {total}, Povodňový režim: {flood}, Priamy: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Pond: {flood}, Priamy: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Celkem: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Nastavenia Opakovača", + "repeater_basicSettings": "Základné nastavenia", + "repeater_repeaterName": "Opakovacia názov", + "repeater_repeaterNameHelper": "Zobrazenie názvu tohto opakovača", + "repeater_adminPassword": "Heslo administrátora", + "repeater_adminPasswordHelper": "Celý prístupový heslo", + "repeater_guestPassword": "Heslo hosťa", + "repeater_guestPasswordHelper": "Prístupový heslo iba na čítanie", + "repeater_radioSettings": "Nastavenia rádia", + "repeater_frequencyMhz": "Frekvencia (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Power", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Šírka pásma", + "repeater_spreadingFactor": "Šírenie faktoru", + "repeater_codingRate": "Rýchlosť kódovania", + "repeater_locationSettings": "Nastavenia polohy", + "repeater_latitude": "Súradnica", + "repeater_latitudeHelper": "Desatinné zložky (napr. 37.7749)", + "repeater_longitude": "Dĺžka", + "repeater_longitudeHelper": "Desatinné zložky (napr. -122.4194)", + "repeater_features": "Funkcie", + "repeater_packetForwarding": "Riadenie prienikov", + "repeater_packetForwardingSubtitle": "Povolte opakovač na smerovanie paketov.", + "repeater_guestAccess": "Prístup pre hostí", + "repeater_guestAccessSubtitle": "Umožniť prístup hosta iba na čítanie.", + "repeater_privacyMode": "Režim ochrany súkromia", + "repeater_privacyModeSubtitle": "Skryť meno/poloha v reklamách", + "repeater_advertisementSettings": "Nastavenia reklamy", + "repeater_localAdvertInterval": "Lokálna reklamná časová obdoba", + "repeater_localAdvertIntervalMinutes": "{minutes} minút", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Interval reklamnej povodňovej reklamy", + "repeater_floodAdvertIntervalHours": "{hours} hodín", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Šifrovaný reklamný interval", + "repeater_dangerZone": "Nebezpečná zóna", + "repeater_rebootRepeater": "Restart Repetér", + "repeater_rebootRepeaterSubtitle": "Resetovať vysielací prístroj", + "repeater_rebootRepeaterConfirm": "Ste si istý, že chcete tento opakovač restartovať?", + "repeater_regenerateIdentityKey": "Generovať kľúč identity", + "repeater_regenerateIdentityKeySubtitle": "Generovať nový pár verejných/privátnych kľúčov", + "repeater_regenerateIdentityKeyConfirm": "Toto vytvorí nový identitu pre opakovač. Pokračovať?", + "repeater_eraseFileSystem": "Vymažať Systémový Reťazec", + "repeater_eraseFileSystemSubtitle": "Formátovať systém opakujúcich sa súborov", + "repeater_eraseFileSystemConfirm": "VAROVANIE: Toto zmaže všetky dáta na opakovači. To sa nedá zrušiť!", + "repeater_eraseSerialOnly": "Odstránenie je dostupné len cez sériové rozhranie.", + "repeater_commandSent": "Poforovaný príkaz: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Chyba pri odeslaní príkazu: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "Potvrdiť", + "repeater_settingsSaved": "Nastavenia boli uložené úspešne.", + "repeater_errorSavingSettings": "Chyba pri ukladaní nastavení: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Obnoviť základné nastavenia", + "repeater_refreshRadioSettings": "Obnoviť Nastavenia Rádií", + "repeater_refreshTxPower": "Obnoviť TX napájanie", + "repeater_refreshLocationSettings": "Obnoviť Nastavenia Miesta", + "repeater_refreshPacketForwarding": "Obnoviť smerovanie paketov", + "repeater_refreshGuestAccess": "Obnoviť prístup hosťa", + "repeater_refreshPrivacyMode": "Obnoviť Ochranný režim", + "repeater_refreshAdvertisementSettings": "Obnoviť nastavenia reklamy", + "repeater_refreshed": "{label} sa znova načítalo", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Chyba pri obnovení {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Opakovacia CLI", + "repeater_debugNextCommand": "Oprava Nasledujúceho Príkaz", + "repeater_commandHelp": "Pomoc", + "repeater_clearHistory": "Vymazať históriu", + "repeater_noCommandsSent": "Zatiaľ neboli odeslané žiadne príkazy.", + "repeater_typeCommandOrUseQuick": "Zadajte príkaz nižšie alebo použite rýchle príkazy", + "repeater_enterCommandHint": "Zadajte príkaz...", + "repeater_previousCommand": "Predchádzajúci príkaz", + "repeater_nextCommand": "Nasledujúci príkaz", + "repeater_enterCommandFirst": "Zadajte najprv príkaz", + "repeater_cliCommandFrameTitle": "Rámok Príkaz CLI", + "repeater_cliCommandError": "Chyba: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Zísť meno", + "repeater_cliQuickGetRadio": "Zísť po rádiu", + "repeater_cliQuickGetTx": "Zísť TX", + "repeater_cliQuickNeighbors": "Súsezný", + "repeater_cliQuickVersion": "Verzia", + "repeater_cliQuickAdvertise": "Reklama", + "repeater_cliQuickClock": "Hodiny", + "repeater_cliHelpAdvert": "Odosiela reklamnú balíček.", + "repeater_cliHelpReboot": "Resetuje zariadenie. (pozor, môže dôjsť k 'Timeoutu', čo je normálne)", + "repeater_cliHelpClock": "Zobrazuje aktuálny čas podľa hodiniek zariadenia.", + "repeater_cliHelpPassword": "Nastaví nový administrátorský prístupový údaj pre zariadenie.", + "repeater_cliHelpVersion": "Zobrazuje verziu zariadenia a dátum zostavenia firmvéru.", + "repeater_cliHelpClearStats": "Resetuje rôzne štatistické počítadlá na nulu.", + "repeater_cliHelpSetAf": "Nastavuje časový faktor.", + "repeater_cliHelpSetTx": "Nastavenie vysielacej sily LoRa v dBm. (potrebuje sa reštart na aplikáciu)", + "repeater_cliHelpSetRepeat": "Umožňuje alebo vypína zopakovaný príspevok pre tento uzol.", + "repeater_cliHelpSetAllowReadOnly": "(Server miestnosti) Ak je 'zapnuté', potom bude povolený prístup s prázdnym heslom, ale nebude možné posielať správu do miestnosti. (iba čítať).", + "repeater_cliHelpSetFloodMax": "Nastavuje maximálny počet skokov pre vstupný povelový paket (ak je >= max, paket nie je preposlaný)", + "repeater_cliHelpSetIntThresh": "Nastavuje hranicu ruživeho ladenia (v dB). Predvolené je 14. Nastavením na 0 sa vypne detekcia ruživeho ladenia kanálu.", + "repeater_cliHelpSetAgcResetInterval": "Nastavuje interval na reštartovanie Auto Gain Controlleru. Nastavenie na 0 vypne funkciu.", + "repeater_cliHelpSetMultiAcks": "Povolí alebo pozastaví funkciiu \"dvojité potvrdenia\".", + "repeater_cliHelpSetAdvertInterval": "Nastavuje interval časovača v minútach na odošle miestny (bezprostredný) reklamný paket. Nastavenie na 0 vypne funkciu.", + "repeater_cliHelpSetFloodAdvertInterval": "Nastavuje interval časovača v hodinách na odeslanie reklamnej vlne. Nastavenie na 0 vypne.", + "repeater_cliHelpSetGuestPassword": "Nastavuje/aktualizuje heslo hosťa. (pre opakované pripojenia môžu hosťovské prihlásenia posielať požadanie \"Get Stats\")", + "repeater_cliHelpSetName": "Nastaví názov reklamy.", + "repeater_cliHelpSetLat": "Nastaví geografickú šírku reklamnej mapy. (desatinné stupne)", + "repeater_cliHelpSetLon": "Nastavuje longitudinu reklamnej mapy. (desatinné stupne)", + "repeater_cliHelpSetRadio": "Nastavuje úplne nové parametre rádia a uloží ich do preferencií. Požaduje príkaz \"reboot\" na aplikáciu.", + "repeater_cliHelpSetRxDelay": "Nastavenia (experimentálne) základné (musi byť > 1 pre účel) na aplikáciu mierneho onesenia prijatých paketov, na základe signálu/skóre. Nastavenie na 0 vypne.", + "repeater_cliHelpSetTxDelay": "Nastavuje faktor násobený časom na vzduchu pre paket v režime povodňovej vlny a s náhodným systémom slotov, aby sa oneskorene jeho prenosovanie (s cieľom znížiť pravdepodobnosť kolízii).", + "repeater_cliHelpSetDirectTxDelay": "Podobne ako txdelay, ale pre aplikáciu náhodného oneskorenia pri preposlaní paketov v režime priameho prenosu.", + "repeater_cliHelpSetBridgeEnabled": "Aktivovať/Zatvárať most.", + "repeater_cliHelpSetBridgeDelay": "Nastaviť odklad pred retransmisiou paketov.", + "repeater_cliHelpSetBridgeSource": "Zvolte, či bude most retransmitovať prijaté alebo vysielané balíčky.", + "repeater_cliHelpSetBridgeBaud": "Nastavte sériový link baudrate pre rs232 mosty.", + "repeater_cliHelpSetBridgeSecret": "Nastaviť tajomstvo mosta pre eshnow mosty.", + "repeater_cliHelpSetAdcMultiplier": "Nastavuje vlastný faktor na úpravu nahlásenej batériovej napätia (podporované len na vybraných doskách).", + "repeater_cliHelpTempRadio": "Nastaví dočasné rádiové parametre pre zadaný počet minút, po skončení sa vráti k pôvodným rádiovým parametrom. (nepočuva sa do preferencií).", + "repeater_cliHelpSetPerm": "Zmení ACL. Odstráni zodpovedný záznam (podľa prefixa pubkey), ak je \"permissions\" rovné 0. Pridá nový záznam, ak je pubkey-hex plnej dĺžky a momentálne sa nenachádza v ACL. Aktualizuje záznam podľa zodpovedajúceho prefixa pubkey. Bitové oprávnenia sa líšia podľa funkčnej roly, ale nízke 2 bity sú: 0 (Hostiteľ), 1 (Čítanie len), 2 (Čítanie a zápis), 3 (Správca).", + "repeater_cliHelpGetBridgeType": "Zísť typ mosta: žiadny, rs232, espnow", + "repeater_cliHelpLogStart": "Začína protokolovanie balíkov do systému súborov.", + "repeater_cliHelpLogStop": "Zastaví protokolovanie paketov do systémového súboru.", + "repeater_cliHelpLogErase": "Odstráni záznamy z balíkov z systému súborov.", + "repeater_cliHelpNeighbors": "Zobrazuje zoznam iných repeaterových uzlov zasielaných cez zero-hop reklamy. Každý riadok je id-prefix-hex:timestamp:snr-times-4", + "repeater_cliHelpNeighborRemove": "Odstráni prvú zhodujúcu položku (podľa prefixu pubkey (hex)) z zoznamu susedov.", + "repeater_cliHelpRegion": "(len sériál) Zobrazuje všetky definované regióny a aktuálne povolenia pre povodňové situácie.", + "repeater_cliHelpRegionLoad": "Poznámka: toto je špeciálna multi-príkázová inštancia. Každé nasledujúce príkaza je názov oblasti (zapustený s medzerami na indikáciu hierarchického pomeru, s minimálne jednou medzerou). Ukončené odeslaním prázdnej platnej linky/príkazu.", + "repeater_cliHelpRegionGet": "Hľadá región s daným príponou názvu (alebo \"\\\" pre globálny rozsah). Odpovedá \"-> región-název (rodič-název) 'F'\"", + "repeater_cliHelpRegionPut": "Pridá alebo aktualizuje definíciu regiónu s daným menom.", + "repeater_cliHelpRegionRemove": "Odstráni definíciu oblasti s daným názvom. (musí zodpovedať presne a nemala by mať podoblasti)", + "repeater_cliHelpRegionAllowf": "Nastavuje povolenie 'P'lávu pre zadanú oblasť. ('' pre globálny/dedičský rozsah)", + "repeater_cliHelpRegionDenyf": "Odstráni povolenie 'F'lood' pre zadanú oblasť. (UPOZORNENIE: v tejto fáze nie je odporúčané ho používať na globálnom/dedskom rozsahu!!).", + "repeater_cliHelpRegionHome": "Odpovedá s aktuálnou 'domovskou' oblasťou. (Poznámka aplikovaná zatiaľ nikde, vyhradené na budúce)", + "repeater_cliHelpRegionHomeSet": "Nastaví 'domovskú' oblasť.", + "repeater_cliHelpRegionSave": "Uloží zoznam/mapu regiónov do úložiska.", + "repeater_cliHelpGps": "Zobrazuje stav GPS. Ak je GPS vypnutý, odpovedá len \"off\", ak je zapnutý, odpovedá s \"on\", stavom, fixom a počtom satelitov.", + "repeater_cliHelpGpsOnOff": "Prepínač stavu GPS napájania.", + "repeater_cliHelpGpsSync": "Synchronizuje čas uzla s GPS hodinami.", + "repeater_cliHelpGpsSetLoc": "Nastaví polohu uzla na GPS súradnice a uloží preferencie.", + "repeater_cliHelpGpsAdvert": "Poskytuje konfiguráciu reklamy pre uzol:\n- žiadna: nezahrňte polohu do reklám\n- zdieľať: zdieľajte GPS polohu (z SensorManager)\n- nastavenia: zobrazujte polohu uloženú v nastaveniach", + "repeater_cliHelpGpsAdvertSet": "Nastavuje konfiguráciu reklamy na zadané miesto.", + "repeater_commandsListTitle": "Zoznam príkazov", + "repeater_commandsListNote": "Poznámka: pre rôzne príkazy \"set ...\" existuje aj príkaz \"get ...\".", + "repeater_general": "Obecné", + "repeater_settingsCategory": "Nastavenia", + "repeater_bridge": "Most", + "repeater_logging": "Záznamy", + "repeater_neighborsRepeaterOnly": "Súseznýci (iba opakovač)", + "repeater_regionManagementRepeaterOnly": "Správa regiónov (iba opakovač)", + "repeater_regionNote": "Regionové príkazy boli zavádzané na správu regionálnych definícií a oprávnení.", + "repeater_gpsManagement": "Správa GPS", + "repeater_gpsNote": "GPS príkaz bol zavádzaný na riadenie lokalitných tém.", + "telemetry_receivedData": "Obdolené Telemetrické dáta", + "telemetry_requestTimeout": "Požiadavka telemetrie zlyhala.", + "telemetry_errorLoading": "Chyba pri načítaní telemetrie: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "Nejsú dostupné žiadne údaje z telemetrie.", + "telemetry_channelTitle": "Kanál {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Batéria", + "telemetry_voltageLabel": "Napätie", + "telemetry_mcuTemperatureLabel": "MCU teplota", + "telemetry_temperatureLabel": "Teplota", + "telemetry_currentLabel": "Aktuálne", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Cesta balíka", + "channelPath_viewMap": "Zobraziť mapu", + "channelPath_otherObservedPaths": "Ostatné pozorovacie cesty", + "channelPath_repeaterHops": "Skoky opakovača", + "channelPath_noHopDetails": "Podrobnosti o balíčku zatiaľ nie sú dostupné.", + "channelPath_messageDetails": "Podrobnosti o zprávach", + "channelPath_senderLabel": "Posielateľ", + "channelPath_timeLabel": "Čas", + "channelPath_repeatsLabel": "Opakovanie", + "channelPath_pathLabel": "Cesta {index}", + "channelPath_observedLabel": "Pozorované", + "channelPath_observedPathTitle": "Sledovaný postup {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "Žiadne údaje o polohe", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Neznáme", + "channelPath_floodPath": "Povodňová", + "channelPath_directPath": "Priamo", + "channelPath_observedZeroOf": "0 z {total} skokov", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} z {total} skokov", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Mapa Trasy", + "channelPath_noRepeaterLocations": "Pre túto cestu nie je dostupných žiadne polohy opakovačov.", + "channelPath_primaryPath": "Cesta {index} (Hlavná)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Cesta", + "channelPath_observedPathHeader": "Sledovaná cesta", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "Pre toto balíček nie sú dostupné údaje o skokoch.", + "channelPath_unknownRepeater": "Neznáme opakovače", + "listFilter_tooltip": "Filtrovať a triediť", + "listFilter_sortBy": "Triediť podľa", + "listFilter_latestMessages": "Posledné správy", + "listFilter_heardRecently": "Nedávno počuli.", + "listFilter_az": "A-Z", + "listFilter_filters": "Filtre", + "listFilter_all": "Všetko", + "listFilter_users": "Používatelia", + "listFilter_repeaters": "Opakovadlá", + "listFilter_roomServers": "Servéry miestnosti", + "listFilter_unreadOnly": "Nezaregistrované len", + "listFilter_newGroup": "Nová skupina" +} diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb new file mode 100644 index 0000000..8a8dc59 --- /dev/null +++ b/lib/l10n/app_sl.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "sl", + "appTitle": "MeshCore Open", + "nav_contacts": "Kontakti", + "nav_channels": "Kanali", + "nav_map": "Karta", + "common_cancel": "Prekliči", + "common_connect": "Poveži se", + "common_unknownDevice": "Nepoznano naprave", + "common_save": "Shrani", + "common_delete": "Izbrisati", + "common_close": "Zapri", + "common_edit": "Uredi", + "common_add": "Dodaj", + "common_settings": "Nastavitve", + "common_disconnect": "Odklopiti", + "common_connected": "Povezano", + "common_disconnected": "Odprto", + "common_create": "Ustvari", + "common_continue": "Poudarki", + "common_share": "Deliti", + "common_copy": "Kopiraj", + "common_retry": "Ponoviti", + "common_hide": "Skrita", + "common_remove": "Izbrisati", + "common_enable": "Omogoči", + "common_disable": "Izklopiti", + "common_reboot": "Ponoviti", + "common_loading": "Naložanje...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Skeniram za naprave...", + "scanner_connecting": "Povezujem se...", + "scanner_disconnecting": "Odklapljam se...", + "scanner_notConnected": "Nezavezan", + "scanner_connectedTo": "Povezan s {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Iskanje naprav MeshCore...", + "scanner_tapToScan": "Nagneš na skeniranje za najdene naprave MeshCore.", + "scanner_connectionFailed": "Pošlo je z povezavo: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Prekliči", + "scanner_scan": "Skeniraj", + "device_quickSwitch": "Hitro preklopiti", + "device_meshcore": "MeshCore", + "settings_title": "Nastavitve", + "settings_deviceInfo": "Informacije o napravei", + "settings_appSettings": "Nastavitve aplikacije", + "settings_appSettingsSubtitle": "Obveščanja, sporoščanje in zemljevidi.", + "settings_nodeSettings": "Nastavitve časa", + "settings_nodeName": "Ime omrežno mesto", + "settings_nodeNameNotSet": "Nezavedeno", + "settings_nodeNameHint": "Vnesite ime časa", + "settings_nodeNameUpdated": "Ime posodobljeno", + "settings_radioSettings": "Nastavitve radija", + "settings_radioSettingsSubtitle": "Frekvenca, moč, razširni faktor", + "settings_radioSettingsUpdated": "Radio nastavitve posodobljene", + "settings_location": "Lokacija", + "settings_locationSubtitle": "GPS koordinate", + "settings_locationUpdated": "Lokacija posodobljena", + "settings_locationBothRequired": "Vnesite širino in dolžino.", + "settings_locationInvalid": "Neveljna zemeljska širina ali dolžina.", + "settings_latitude": "Širina", + "settings_longitude": "Dolžina", + "settings_privacyMode": "Mod podjetja", + "settings_privacyModeSubtitle": "Skrita imena/lokacije v oglasih", + "settings_privacyModeToggle": "Omogoči način zasebnosti, da skrijemo tvoje ime in lokacijo v oglasih.", + "settings_privacyModeEnabled": "Privatni režim je omogočen.", + "settings_privacyModeDisabled": "Privatni režim je onemogočen.", + "settings_actions": "Akcije", + "settings_sendAdvertisement": "Pošlji Oglas", + "settings_sendAdvertisementSubtitle": "Trenutna prisotnost v oddajah", + "settings_advertisementSent": "Oglas poslan", + "settings_syncTime": "Ugasniti čas", + "settings_syncTimeSubtitle": "Nastavi uro naprave v čas telefona", + "settings_timeSynchronized": "Sinhronizirano po času", + "settings_refreshContacts": "Ponovno obišči kontakte", + "settings_refreshContactsSubtitle": "Ponovno naloži seznam kontaktov iz naprave", + "settings_rebootDevice": "Restart Naprave", + "settings_rebootDeviceSubtitle": "Ponovite zažetek naprave MeshCore", + "settings_rebootDeviceConfirm": "Ste prepričani, da želite ponovno zagon napravke? Boste odvisni od omrežja.", + "settings_debug": "Napravi popravek", + "settings_bleDebugLog": "Logarjev zapis BLE", + "settings_bleDebugLogSubtitle": "Navodila BLE, odgovori in surovo podatkovno", + "settings_appDebugLog": "Log zapiske aplikacije", + "settings_appDebugLogSubtitle": "Prijavni sporočila aplikacije", + "settings_about": "Oglejte si", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "MeshCore Odprtokodni Projekt 2024", + "settings_aboutDescription": "Odprtokodni Flutter kličnik za naprave za LoRa mrežo MeshCore.", + "settings_infoName": "Ime", + "settings_infoId": "ID", + "settings_infoStatus": "Status", + "settings_infoBattery": "Baterija", + "settings_infoPublicKey": "Ključ javnega tipa", + "settings_infoContactsCount": "Število kontaktov", + "settings_infoChannelCount": "Število kanalov", + "settings_presets": "Prednastavitve", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Frekvenca (MHz)", + "settings_frequencyHelper": "300,00 - 2500,00", + "settings_frequencyInvalid": "Neveljčna frekvenca (300-2500 MHz)", + "settings_bandwidth": "Pasovna širina", + "settings_spreadingFactor": "Razširitveni faktor", + "settings_codingRate": "Programska hitrost", + "settings_txPower": "TX Moč (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Neveljaven TX moč (0-22 dBm)", + "settings_longRange": "Dolenje območje", + "settings_fastSpeed": "Hitra hitrost", + "settings_error": "Napaka: {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "Nastavitve aplikacije", + "appSettings_appearance": "Prikaži", + "appSettings_theme": "Tema", + "appSettings_themeSystem": "Predpomnilnik sistema", + "appSettings_themeLight": "Luč", + "appSettings_themeDark": "Temno", + "appSettings_language": "Jezik", + "appSettings_languageSystem": "Sistemska privzeta vrednost", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Obveščanja", + "appSettings_enableNotifications": "Omogoči obveščanje", + "appSettings_enableNotificationsSubtitle": "Prejmujte obvestila o sporočilih in oglasih", + "appSettings_notificationPermissionDenied": "Odobritev obvestila zavrnjena", + "appSettings_notificationsEnabled": "Obvestila omogočena", + "appSettings_notificationsDisabled": "Obvestila so izklopljena", + "appSettings_messageNotifications": "Obvestila", + "appSettings_messageNotificationsSubtitle": "Pokaži obvestilo ob prejemu novih sporočil.", + "appSettings_channelMessageNotifications": "Obvestila o sporočilih kanala", + "appSettings_channelMessageNotificationsSubtitle": "Pokaži obvestilo ob prejemanju sporočil kanala", + "appSettings_advertisementNotifications": "Opozorila o oglasih", + "appSettings_advertisementNotificationsSubtitle": "Pokaži obvestilo, ko so novi vozlišči odkrivljeni.", + "appSettings_messaging": "Komuniciranje", + "appSettings_clearPathOnMaxRetry": "Ponovite pot do cilja na največjem štetju", + "appSettings_clearPathOnMaxRetrySubtitle": "Ponovi pot zimske obveščevalne poti po 5 neuspešnih poskusih pošiljanja", + "appSettings_pathsWillBeCleared": "Potnice bodo očiščene po 5 neuspešnih poskusih.", + "appSettings_pathsWillNotBeCleared": "Potniški poti ne bodo samodejno čiščeni.", + "appSettings_autoRouteRotation": "Avtomatsko Občutke in Rotacije", + "appSettings_autoRouteRotationSubtitle": "Med spreminjanjem med najboljšimi potmi in plovilnim načinom", + "appSettings_autoRouteRotationEnabled": "Samodejno krmilno rotiranje omogočeno", + "appSettings_autoRouteRotationDisabled": "Samodejno krmilno rotiranje je onemogočeno", + "appSettings_battery": "Baterija", + "appSettings_batteryChemistry": "Razem z možnostmi", + "appSettings_batteryChemistryPerDevice": "Nastavitve za naprave ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Povežite se z napravo za izbiro", + "appSettings_batteryNmc": "18650 NMC (3,0-4,2V)", + "appSettings_batteryLifepo4": "LiFePO4 (2,6–3,65 V)", + "appSettings_batteryLipo": "LiPo (3,0-4,2V)", + "appSettings_mapDisplay": "Prikaz zemljevide", + "appSettings_showRepeaters": "Prikaži ponovitve", + "appSettings_showRepeatersSubtitle": "Prikaži ponovljalne notranjosti na zemljeploscu", + "appSettings_showChatNodes": "Prikaži čakalne notranjosti", + "appSettings_showChatNodesSubtitle": "Prikaži pogovorni pike na zemljeploscu", + "appSettings_showOtherNodes": "Pokaži druge vozlišča", + "appSettings_showOtherNodesSubtitle": "Pokaži druge vrste notranjih elementov na zemljevalu.", + "appSettings_timeFilter": "Filtri po času", + "appSettings_timeFilterShowAll": "Pokaži vse notranje elemente", + "appSettings_timeFilterShowLast": "Pokaži notranjosti iz zadnjih {hours} ur", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Filtri časa zemljevida", + "appSettings_showNodesDiscoveredWithin": "Pokaži notranje čepke, odkrivene v:", + "appSettings_allTime": "Vse čase", + "appSettings_lastHour": "Minuto nazaj", + "appSettings_last6Hours": "Zadnjih 6 ur", + "appSettings_last24Hours": "Zadnjih 24 ur", + "appSettings_lastWeek": "Lepošno", + "appSettings_offlineMapCache": "Omrezni Poudni Arhiv", + "appSettings_noAreaSelected": "Nizkana označena površina", + "appSettings_areaSelectedZoom": "Izbrano območje (povečava {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Napravi popravek", + "appSettings_appDebugLogging": "Programski Log", + "appSettings_appDebugLoggingSubtitle": "Log aplikacijske debug sporočila za odpravljanje težav", + "appSettings_appDebugLoggingEnabled": "Omogočeno zaznamovanje napak v aplikaciji", + "appSettings_appDebugLoggingDisabled": "Programski logi aplikacije so onemogočeni.", + "contacts_title": "Kontakti", + "contacts_noContacts": "Še ni kontaktov.", + "contacts_contactsWillAppear": "Kontakti se bodo prikazali, ko naprave oglasijo.", + "contacts_searchContacts": "Iskanje kontaktov...", + "contacts_noUnreadContacts": "Nerešeno kontaktov.", + "contacts_noContactsFound": "Niti ena osebe ali skupine ni najdena.", + "contacts_deleteContact": "Izbrisati Kontakt", + "contacts_removeConfirm": "Izbrisati {contactName} iz kontaktov?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Upravljajte Ponovitve", + "contacts_roomLogin": "Vnos v sobo", + "contacts_openChat": "Odprta kleta", + "contacts_editGroup": "Uredi Skupino", + "contacts_deleteGroup": "Izbrisati Skupino", + "contacts_deleteGroupConfirm": "Odpovedati {groupName}?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Novo skupino", + "contacts_groupName": "Skupina imena", + "contacts_groupNameRequired": "Ime skupine je obvezno.", + "contacts_groupAlreadyExists": "Skupina \"{name}\" že obstaja", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Filtri kontakt\\,...", + "contacts_noContactsMatchFilter": "Niti ena osebe ne ustreza vašemu kriteriju.", + "contacts_noMembers": "Nič članov.", + "contacts_lastSeenNow": "Datum zadnjega vpisa zdaj", + "contacts_lastSeenMinsAgo": "Zadnjič videti {minutes} minut nazaj", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Zadnjič ogledan pred 1 uro.", + "contacts_lastSeenHoursAgo": "Zadnjič videti {hours} ur nazaj", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Zadnjič ogledan pred 1 dnem", + "contacts_lastSeenDaysAgo": "Zadnjič videti {days} dni nazaj", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Kanali", + "channels_noChannelsConfigured": "Nekonfigurirane kanale", + "channels_addPublicChannel": "Dodaj Objavni Kanal", + "channels_searchChannels": "Poišči kanale...", + "channels_noChannelsFound": "Niti kanalov najti ni.", + "channels_channelIndex": "Kanal {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Hashtag kanal", + "channels_public": "javno", + "channels_private": "Zasebno", + "channels_publicChannel": "Ogljišna skupina", + "channels_privateChannel": "Zatemniščen kanal", + "channels_editChannel": "Uredi kanal", + "channels_deleteChannel": "Pošlji kanal", + "channels_deleteChannelConfirm": "Izbrisati \"{name}\"? To se ne da povrniti.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Kanal \"{name}\" izbrisan.", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Dodaj Kanal", + "channels_channelIndexLabel": "Indeks kanala", + "channels_channelName": "Ime kanala", + "channels_usePublicChannel": "Uporabi javni kanal", + "channels_standardPublicPsk": "Standardni javni PSK", + "channels_pskHex": "PSK (Šestnajstbinska)", + "channels_generateRandomPsk": "Generiraj naključni PSK", + "channels_enterChannelName": "Vnesi ime kanala", + "channels_pskMustBe32Hex": "PSK mora biti 32 heksadecimalnih znakov.", + "channels_channelAdded": "Kanal \"{name}\" dodan", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Uredi Kanal {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "Kompresija SMAZ", + "channels_channelUpdated": "Kanal {name} je bil posodobljen", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "javna skupnost dodana", + "channels_sortBy": "Sortiraj po", + "channels_sortManual": "Ročno", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "Najnovejše sporočilo", + "channels_sortUnread": "Nerešeno", + "chat_noMessages": "Še ni sporočil.", + "chat_sendMessageToStart": "Pošlji sporočilo za začetek.", + "chat_originalMessageNotFound": "Opozorilo: Sporočilo ni bilo najdeno", + "chat_replyingTo": "Odgovarjanje {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Odpošlji odgovor {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Lokacija", + "chat_sendMessageTo": "Pošlji sporočilo {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Vnesite sporočilo...", + "chat_messageTooLong": "Pošiljanje sporočila je onemogočeno, saj je preveliko (maksimalno {maxBytes} bajt).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Pošljeno sporočilo", + "chat_messageDeleted": "Pošiljanje sporočila izbrisano", + "chat_retryingMessage": "Ponovna poskus.", + "chat_retryCount": "Ponovit {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "Pošlji GIF", + "chat_reply": "Odpošlji", + "chat_addReaction": "Dodaj Reakcijo", + "chat_me": "jaz", + "emojiCategorySmileys": "Emoji", + "emojiCategoryGestures": "Gestikulacije", + "emojiCategoryHearts": "Srce", + "emojiCategoryObjects": "Predmeti", + "gifPicker_title": "Izberi GIF", + "gifPicker_searchHint": "Iskalite GIF-e...", + "gifPicker_poweredBy": "Naprodno z GIPHY", + "gifPicker_noGifsFound": "Niti GIF-jev najti ni.", + "gifPicker_failedLoad": "Neuspešno je naložilo GIF-e", + "gifPicker_failedSearch": "Posodobit neuspešno.", + "gifPicker_noInternet": "Ni internetne povezave", + "debugLog_appTitle": "Log zapiske aplikacije", + "debugLog_bleTitle": "Logarjev zapis BLE", + "debugLog_copyLog": "Kopiraj zapiske", + "debugLog_clearLog": "Pasters log", + "debugLog_copied": "Kopirana belež poteka.", + "debugLog_bleCopied": "Kopirana beležke iz BLE", + "debugLog_noEntries": "Še ni ustvarjenih debug zapisov.", + "debugLog_enableInSettings": "Omogoči beleženje napak v aplikaciji v nastavitvah", + "debugLog_frames": "Okna", + "debugLog_rawLogRx": "Svež Log-RX", + "debugLog_noBleActivity": "Šele začnite z aktivnostjo BLE.", + "debugFrame_length": "Izhodni rob: {count} bajtov", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Navodilo: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Obvestilo:", + "debugFrame_destinationPubKey": "- Destinirano Ključno Besedilo: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Časovnik: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Ploki: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- Tip besedila: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Preprosto", + "debugFrame_text": "- Tekst: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Hex Dump:", + "chat_pathManagement": "Upravljanje poti", + "chat_routingMode": "Navodilo za usmerjevalni način", + "chat_autoUseSavedPath": "Avto (uporabi shranjeno pot)", + "chat_forceFloodMode": "Nasilje obvezati v način", + "chat_recentAckPaths": "Nedavni poti ACK (tap za uporabo):", + "chat_pathHistoryFull": "Zapiske o poti so popolni. Izbriši vnose, da dodaš nove.", + "chat_hopSingular": "skoč", + "chat_hopPlural": "škrabec", + "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "Uspešni", + "chat_removePath": "Izbriši pot", + "chat_noPathHistoryYet": "Še ni shranjenih poti.\nPošlji sporočilo za odkrivanje poti.", + "chat_pathActions": "Potni ukazi:", + "chat_setCustomPath": "Nastavi Prilozeno Pot", + "chat_setCustomPathSubtitle": "Ročno določite potniško pot.", + "chat_clearPath": "Čista pot", + "chat_clearPathSubtitle": "Ob naslednji pošiljanju znova zbrati.", + "chat_pathCleared": "Pot je očiščena. Naslednje sporočilo bo ponovno odkril pot.", + "chat_floodModeSubtitle": "Uporabi tipko usmerjevanja v meniju aplikacije.", + "chat_floodModeEnabled": "Narejena je bila omrežna modaliteta. Vklopi jo znova preko ikone v meniju aplikacije.", + "chat_fullPath": "Polni pot", + "chat_pathDetailsNotAvailable": "Podrobnosti poti zaenkrat niso na voljo. Poskusite poslati sporočilo za osvežitev.", + "chat_pathSetHops": "Pot nastavljen: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Shrano lokalno. Povežite se za sinhronizacijo.", + "chat_pathDeviceConfirmed": "Naprave potrjeno.", + "chat_pathDeviceNotConfirmed": "Naprave še niso potrdile.", + "chat_type": "Vnesite", + "chat_path": "Pot", + "chat_publicKey": "Ključ javnega tipa", + "chat_compressOutgoingMessages": "Stisnite izhodne sporočila", + "chat_floodForced": "Porolni (nasilje).", + "chat_directForced": "Nezglašen (nasilje)", + "chat_hopsForced": "{count} skoki (nasilje)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Preplavljenje (avtomatizirano)", + "chat_direct": "Neposredni", + "chat_poiShared": "Deljeno točke MN", + "chat_unread": "Nerešeno: {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Mapa omrežja", + "map_noNodesWithLocation": "Nihče od notranjih elementov nima podatkov o lokaciji.", + "map_nodesNeedGps": "Omrežje morajo deliti svoje GPS koordinate,\nda se prikazajo na zemljeobrazniku.", + "map_nodesCount": "Omize: {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Žigovi: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Čistemar", + "map_repeater": "Ponovitelj", + "map_room": "Soba", + "map_sensor": "Senzor", + "map_pinDm": "Zavežite (DM)", + "map_pinPrivate": "Zasebno označit", + "map_pinPublic": "Oznaka (javna)", + "map_lastSeen": "Zadnjič Zazet", + "map_disconnectConfirm": "Ste prepričani, da želite se odklopiti s tega naprave?", + "map_from": "Od", + "map_source": "Vir", + "map_flags": "Zapestnice", + "map_shareMarkerHere": "Delite točke tukaj.", + "map_pinLabel": "Oznaka za pritrditev", + "map_label": "Oznaka", + "map_pointOfInterest": "Točka zanimivosti", + "map_sendToContact": "Pošlji v kontakt", + "map_sendToChannel": "Pošlji v kanal", + "map_noChannelsAvailable": "Nihče kanalov na voljo.", + "map_publicLocationShare": "Deljenje javne lokacije", + "map_publicLocationShareConfirm": "Kljubite boste delili lokacijo v {channelLabel}. Ta kanal je javno dostopen in vsak, ki ima PSK, ga lahko vidi.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Povežite se z napravo za deljenje oznak.", + "map_filterNodes": "Filtirirajte člene", + "map_nodeTypes": "Vrste knope", + "map_chatNodes": "Čuti zvezde", + "map_repeaters": "Ponovljalniki", + "map_otherNodes": "Druge vozlišča", + "map_keyPrefix": "Predpona ključa", + "map_filterByKeyPrefix": "Filtri po predpomniku ključa", + "map_publicKeyPrefix": "Predifika javnega ključa", + "map_markers": "Označitelji", + "map_showSharedMarkers": "Pokaži skupno označenja", + "map_lastSeenTime": "Datum zadnjega vpogleda", + "map_sharedPin": "Deljeno naslovno geslo", + "map_joinRoom": "Pridružiti sobo", + "map_manageRepeater": "Upravljajte Ponovitve", + "mapCache_title": "Omrezni predpomnilnik zemljeških zemljejevskih slik", + "mapCache_selectAreaFirst": "Izberite območje za prvo predpomnilnik.", + "mapCache_noTilesToDownload": "Nihče slik ne bo naložil za to območje.", + "mapCache_downloadTilesTitle": "Naloži ploščice", + "mapCache_downloadTilesPrompt": "Naložiť {count} plošč za uporabo v režimu brez povezave?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Naloži", + "mapCache_cachedTiles": "Pospešeno shranjeni {count} plošč", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Shranjeni {downloaded} ploščad ({failed} neuspešno)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Ponovite arhiv za offline način", + "mapCache_clearOfflineCachePrompt": "Izbriši vse predpomnilnikovane kartografske ploščice?", + "mapCache_offlineCacheCleared": "Omrezni predpomnik je bil izbrisal.", + "mapCache_noAreaSelected": "Nizona označena površina", + "mapCache_cacheArea": "Omanski prostor", + "mapCache_useCurrentView": "Uporabi trenutni prikaz", + "mapCache_zoomRange": "Občutek razpona", + "mapCache_estimatedTiles": "Predvideni ploščadi: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Naloženo {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Naloži ploščice", + "mapCache_clearCacheButton": "Ponoviti arhiv", + "mapCache_failedDownloads": "Poslovniški izniki: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Takoj", + "time_minutesAgo": "{minutes} minut nazaj", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours}h nazaj", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} dni nazaj", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "ure", + "time_hours": "ure", + "time_day": "dan", + "time_days": "dani", + "time_week": "teden", + "time_weeks": "tedne", + "time_month": "mesec", + "time_months": "mesi", + "time_minutes": "minute", + "time_allTime": "Vse časovno obdobje", + "dialog_disconnect": "Odklopiti", + "dialog_disconnectConfirm": "Ste prepričani, da želite se odklopiti s tega naprave?", + "login_repeaterLogin": "Ponovni vnos", + "login_roomLogin": "Vnos v sobo", + "login_password": "Geslo", + "login_enterPassword": "Vnesite geslo", + "login_savePassword": "Shrani geslo", + "login_savePasswordSubtitle": "Geslo bo shranjeno varno na tem pripravem.", + "login_repeaterDescription": "Vnesite geslo za ponovljalnik, da dostopite do nastavitev in statusa.", + "login_roomDescription": "Vnesite geslo v sobo za dostop do nastavitev in statusa.", + "login_routing": "Usmerjanje", + "login_routingMode": "Navodilo za usmerjevalni način", + "login_autoUseSavedPath": "Avto (uporabi shranjeno pot)", + "login_forceFloodMode": "Nasilje obvezati v način", + "login_managePaths": "Upravljajte Potniške Proti", + "login_login": "Prijava", + "login_attempt": "Poskušajo {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Prijava je bila neuspešna: {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Ponovno naloži", + "common_clear": "Ponoviti", + "path_currentPath": "Trenutna pot: {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Uporablja {count} {count, plural, =1{hop} other{hops}} pot", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Vnesite prilagojeno pot", + "path_currentPathLabel": "Trenutna pot", + "path_hexPrefixInstructions": "Vnesite 2-karakterne heksadecimalne prefixe za vsako skopo, ločeno z zvezekami.", + "path_hexPrefixExample": "Primer: A1,F2,3C (vsak notranji element uporablja prvi bajt svojega javnega ključa)", + "path_labelHexPrefixes": "Pot (heksafixne skrajšave)", + "path_helperMaxHops": "Maksimalno 64 skokov. Vsak prefiks je 2 heksadecimalna znamenja (1 bajt).", + "path_selectFromContacts": "Izberi iz kontaktov:", + "path_noRepeatersFound": "Ne najdenih ponoviteljev ali strežnikov sob.", + "path_customPathsRequire": "Prilojene poti zahtevajo medhodne prenose, ki lahko prenašajo sporočila.", + "path_invalidHexPrefixes": "Neveljačni šesteročlenski prefiksi: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "Pot je prevelika. Dovoljeno največ 64 skokov.", + "path_setPath": "Nastavi Pot", + "repeater_management": "Upravljanje ponovitve", + "repeater_managementTools": "Upravne orodje", + "repeater_status": "Status", + "repeater_statusSubtitle": "Pogledati stanje, statistike in sosede repeatera", + "repeater_telemetry": "Telemetrija", + "repeater_telemetrySubtitle": "Pogledate telemetrijo senzorjev in sistemske statistike", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Pošlji ukazne povelje na ponovitveno enoto.", + "repeater_settings": "Nastavitve", + "repeater_settingsSubtitle": "Konfigurirajte parametre ponovitelja", + "repeater_statusTitle": "Status ponovitelja", + "repeater_routingMode": "Navodilo za usmerjevalni način", + "repeater_autoUseSavedPath": "Avto (uporabi shranjeno pot)", + "repeater_forceFloodMode": "Nasilje obvezati v način", + "repeater_pathManagement": "Upravljanje poti", + "repeater_refresh": "Ponovno obnavljati", + "repeater_statusRequestTimeout": "Zahtev statusa je iztekla.", + "repeater_errorLoadingStatus": "Napaka pri obnašanju: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Informacije o sistemu", + "repeater_battery": "Baterija", + "repeater_clockAtLogin": "Ure (pri prijavi)", + "repeater_uptime": "Čas delovanja", + "repeater_queueLength": "Dolžina čakalne vrste", + "repeater_debugFlags": "Nastavitve odpravilnosti", + "repeater_radioStatistics": "Radio Statistika", + "repeater_lastRssi": "Potredno RSSI", + "repeater_lastSnr": "Nazadnje zabeležena SNR", + "repeater_noiseFloor": "Šumovita raven", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Statistika paketa", + "repeater_sent": "Pošljeno", + "repeater_received": "Prejeto", + "repeater_duplicates": "Duplikati", + "repeater_daysHoursMinsSecs": "{days} dni {hours}h {minutes}m {seconds}s", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Skupno: {total}, Poplava: {flood}, Neposredno: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Skupno: {total}, Poplava: {flood}, Neposredno: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Prah: {flood}, Neposredni: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Skupno: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Nastavitve ponovitelja", + "repeater_basicSettings": "Osnovne nastavitve", + "repeater_repeaterName": "Ime ponovitelja", + "repeater_repeaterNameHelper": "Prikaz imena za ta ponovitelj.", + "repeater_adminPassword": "Admin geslo", + "repeater_adminPasswordHelper": "Polni dostopno geslo", + "repeater_guestPassword": "Geslo gostača", + "repeater_guestPasswordHelper": "Odpovedni dostopni geslo", + "repeater_radioSettings": "Nastavitve Radija", + "repeater_frequencyMhz": "Frekvenca (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Moč", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Pasovna širina", + "repeater_spreadingFactor": "Razširitveni faktor", + "repeater_codingRate": "Programska hitrost", + "repeater_locationSettings": "Nastavitve lokacije", + "repeater_latitude": "Širina", + "repeater_latitudeHelper": "Desetbinske protiure (npr. 37.7749)", + "repeater_longitude": "Dolžina", + "repeater_longitudeHelper": "Desetbinske protiure (npr. -122,4194)", + "repeater_features": "Značilnosti", + "repeater_packetForwarding": "Usmerjanje paketa", + "repeater_packetForwardingSubtitle": "Omogoči ponovitelja za usmerjanje paketov.", + "repeater_guestAccess": "Prijemnik", + "repeater_guestAccessSubtitle": "Omogoči dostop gostom v samo bralni načinu.", + "repeater_privacyMode": "Privatni način", + "repeater_privacyModeSubtitle": "Skrita imena/lokacije v oglasih", + "repeater_advertisementSettings": "Nastavitve oglasnika", + "repeater_localAdvertInterval": "Lokalen Oglasovni Razpon", + "repeater_localAdvertIntervalMinutes": "{minutes} minut", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Razpon Obvestil o Poplavah", + "repeater_floodAdvertIntervalHours": "{hours} ur", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Šifrirana Oglasovalska Trajanje", + "repeater_dangerZone": "Opozorilo", + "repeater_rebootRepeater": "Ponovni zagon Repeaterja", + "repeater_rebootRepeaterSubtitle": "Ponovni zagon ponovitelja.", + "repeater_rebootRepeaterConfirm": "Ste prepričani, da želite ponovno zagon tega ponovitelja?", + "repeater_regenerateIdentityKey": "Ponovite Ključ Identnosti", + "repeater_regenerateIdentityKeySubtitle": "Ustvarite novo par javnih/zasebnih ključev", + "repeater_regenerateIdentityKeyConfirm": "To bo ustvaril novo identiteto za ponavljalnik. Prijavite se?", + "repeater_eraseFileSystem": "Počisti Sustav Vajah", + "repeater_eraseFileSystemSubtitle": "Oblikuj datoteko ponovitve sistema", + "repeater_eraseFileSystemConfirm": "OPOZORILO: To bo izbrisal/a vsa dejstva na ponovilu. To ni mogoče povzvrniti!", + "repeater_eraseSerialOnly": "Brisanje je na voljo samo preko serijske konzole.", + "repeater_commandSent": "Navodilo poslano: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Napaka pri pošiljanju ukaznega: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "Potrdit", + "repeater_settingsSaved": "Nastavitve so shranjene uspešno.", + "repeater_errorSavingSettings": "Napaka pri shranjevanju nastavitev: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Ponovno nastavi osnovne nastavitve", + "repeater_refreshRadioSettings": "Ponovno Nastavitve Radija", + "repeater_refreshTxPower": "Ponovno nastavi TX moč", + "repeater_refreshLocationSettings": "Ponovno Nastavi Nastavitve Lokacije", + "repeater_refreshPacketForwarding": "Ponovno nastavitve usmerjevanja paketa", + "repeater_refreshGuestAccess": "Ponovno nastavitve dostopa gostov", + "repeater_refreshPrivacyMode": "Ponovno aktiviraj način zasebnosti", + "repeater_refreshAdvertisementSettings": "Ponovno nastavi Oglede Oglasi", + "repeater_refreshed": "{label} je bil/a posodobljen/a", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Napaka pri osveževanju {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Ponovitelj CLI", + "repeater_debugNextCommand": "Popravi naslednje ukazne možnosti", + "repeater_commandHelp": "Pomoc", + "repeater_clearHistory": "Ponovi zgodovino", + "repeater_noCommandsSent": "Niti ena ukazne povratne informacije še ni poslana.", + "repeater_typeCommandOrUseQuick": "Vnesite ukaz spodaj ali uporabite hitre ukaze", + "repeater_enterCommandHint": "Vnesite ukaz...", + "repeater_previousCommand": "Prejšnji ukaz", + "repeater_nextCommand": "Naslednja ukazna", + "repeater_enterCommandFirst": "Vnesite ukaz najprej", + "repeater_cliCommandFrameTitle": "Okno ukazne vrstice", + "repeater_cliCommandError": "Napaka: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Dobiti ime", + "repeater_cliQuickGetRadio": "Dobiti Radiopravo", + "repeater_cliQuickGetTx": "Dobiti TX", + "repeater_cliQuickNeighbors": "Sosedi", + "repeater_cliQuickVersion": "Različica", + "repeater_cliQuickAdvertise": "Oglasite", + "repeater_cliQuickClock": "Urnik", + "repeater_cliHelpAdvert": "Pošlje paket oglasov", + "repeater_cliHelpReboot": "Ponastavi naprave. (Opomba, lahko pride do 'Timeouta', kar je normalno)", + "repeater_cliHelpClock": "Prikaže trenutno uro po uri naprave.", + "repeater_cliHelpPassword": "Nastavi novo administracijsko geslo za naprave.", + "repeater_cliHelpVersion": "Prikaže različico naprave in datum izrabe strojne opreme.", + "repeater_cliHelpClearStats": "Ponastavi različne statistične števke na nič.", + "repeater_cliHelpSetAf": "Nastavi časovni koeficient.", + "repeater_cliHelpSetTx": "Nastavi moč LoRa oddajanja v dBm. (za ponovni zagon za uporabo)", + "repeater_cliHelpSetRepeat": "Omogoči ali onemogoči vlogo ponovitelja za tono.", + "repeater_cliHelpSetAllowReadOnly": "(Osebni strežnik) Če je 'vklopljeno', potem bo dovoljeno prijavo z praznim geslom, vendar ne bo mogoče objaviti v sobo. (samo branje).", + "repeater_cliHelpSetFloodMax": "Nastavi največjo število skokov za vstopne poplave (če je >= maks, paket ni usmerjen)", + "repeater_cliHelpSetIntThresh": "Nastavi Prag Interferencij (v dB). Privzeto je 14. Nastavi na 0 za onemogočitev zaznavanja interferenc kanalov.", + "repeater_cliHelpSetAgcResetInterval": "Nastavi časovno razdaljo za ponovni zagon nadzornika Avtomatske uteži. Nastavi na 0 za onemogočanje.", + "repeater_cliHelpSetMultiAcks": "Omogoči ali onemogoči funkcijo \"dvojakih potrdil\".", + "repeater_cliHelpSetAdvertInterval": "Nastavi časovno obmesto v minutah za pošiljanje lokalnega (brezposrednega) napovednega paketa. Nastavi na 0 za onemogočiti.", + "repeater_cliHelpSetFloodAdvertInterval": "Nastavi časovno obmesto v urah za pošiljanje plovilnega oglasnega paketa. Nastavi na 0 za onemogočanje.", + "repeater_cliHelpSetGuestPassword": "Nastavi/posodobi geslo gosta. (za ponovitve lahko gostov prijavi pošiljajo zahtevo \"Get Stats\")", + "repeater_cliHelpSetName": "Nastavi ime oglasnika.", + "repeater_cliHelpSetLat": "Nastavi zemljepisno širino oglaševalskega zemljevida (desetdeljne).", + "repeater_cliHelpSetLon": "Nastavi zemljevidno širino oglasnika. (desetdelne stopnje)", + "repeater_cliHelpSetRadio": "Nastavi popolnoma nove radijske parametre in jih shranjuje v nastavitve. Za uporabo je potrebna \"restart\" ukaz.", + "repeater_cliHelpSetRxDelay": "Nastavitve (eksperimentalne) osnova (mora biti > 1 za učinkovanje) za uporabo rahle zakasnitve prejetih paketov, glede na moč signala/rezultat. Nastavite na 0 za onemogočanje.", + "repeater_cliHelpSetTxDelay": "Nastavi faktor, ki se množi s časom delovanja za paket v načinu poplavnega režima in z randomiziranim sistemom slotov, da odvrne njegovo posredovanje. (da se zmanjša verjetnost kolizij)", + "repeater_cliHelpSetDirectTxDelay": "Ima podobno vrednost kot txdelay, vendar jo lahko uporabite za dodajanje naknadnega zamika pri posredovanju paketov v režimu neposredne prevodi.", + "repeater_cliHelpSetBridgeEnabled": "Omogoči/Preklopi most.", + "repeater_cliHelpSetBridgeDelay": "Nastavi zamik pred ponovnim poslanjem paketov.", + "repeater_cliHelpSetBridgeSource": "Izberite, ali bodo most ponavljali prejeto ali poslan paket.", + "repeater_cliHelpSetBridgeBaud": "Nastavi hitrost serijske povezave za mostove rs232.", + "repeater_cliHelpSetBridgeSecret": "Nastavi skrivni dostop za mostove ESPNOW.", + "repeater_cliHelpSetAdcMultiplier": "Nastavi prilagoditev faktorja za prilagoditev poravnalnega napetosti baterije (podprt le na izbranih ploščah).", + "repeater_cliHelpTempRadio": "Nastavi začasne radio parametre za določeno časovno obdobje, kar po preteku časa vrne originalne radio parametre. (ne shranjuje v preferencije).", + "repeater_cliHelpSetPerm": "Modificira ACL. Odstrani ustreznu vnos (po predponi pubkeyja), če je \"permissions\" enako nič. Dodaja nov vnos, če je pubkey-hex v celoti in trenutno ni v ACL. Posodobi vnos po ustreznem predponi pubkeyja. Bitje dovoljenj se razlikuje glede na firmware vlogo, vendar so prvi dve bitki: 0 (Gost), 1 (Lezenje samo), 2 (Lezenje in pisanje), 3 (Administrator).", + "repeater_cliHelpGetBridgeType": "Dobrodošli pri izbiri vrste mostu: brez, rs232, espnow", + "repeater_cliHelpLogStart": "Začnete beleženje paketov v datotekovni sistem.", + "repeater_cliHelpLogStop": "Ustavite beleženje paketov v datotečno sistem.", + "repeater_cliHelpLogErase": "Izbriše pakete zapisov iz datotek sistema.", + "repeater_cliHelpNeighbors": "Prikaže seznam drugih ponovnih knopov, do katerih je prišlo preko brezposrednih oglasov. Vsaka vrstica je id-prefix-hex:timestamp:snr-times-4", + "repeater_cliHelpNeighborRemove": "Izbriše prvo ustreznu postavko (po predpomnilku pubkey (heks),) iz seznama sosedov.", + "repeater_cliHelpRegion": "(Serija samo) Navaja vse definirane regije in trenutne poplave dovolilnosti.", + "repeater_cliHelpRegionLoad": "Opomba: to je posebna več ukazna pozivna operacija. Vsak naslednji ukaz je ime regije (z lezijami za prikaz hierarhije, z enim ustvarjenim razmislom). Zaključena s pošiljanjem praznega reda/ukaza.", + "repeater_cliHelpRegionGet": "Išče regijo s podanimi imenimi prefiksom (ali \"\\\" za globalni obseg). Odgovori se s \"-> regija-ime (rodič-ime) 'F'\"", + "repeater_cliHelpRegionPut": "Dodaja ali posodobi regijsko definicijo s podanim imenom.", + "repeater_cliHelpRegionRemove": "Izbriše definicijo regije s podanim imenom. (mora se popolnoma ujemati in ne sme imeti podregij)", + "repeater_cliHelpRegionAllowf": "Nastavi dovoljenje 'Nere' za podano regijo. ('' za globalni/dedni obseg)", + "repeater_cliHelpRegionDenyf": "Odstrani dovoljenje 'F'lood' za podano regijo. (OPOZORILO: na tem koraku ni priporočljivo ga uporabljati na globalnem/dednem obsegu!!)", + "repeater_cliHelpRegionHome": "Odgovori z trenutnim 'domovim' območjem. (Opomba je bila še nujno uporabljena, rezervirano za prihodnost)", + "repeater_cliHelpRegionHomeSet": "Nastavi regijo 'domov'.", + "repeater_cliHelpRegionSave": "Shrani seznam/ zemljevzemi regij v shranjevanje.", + "repeater_cliHelpGps": "Pokaže status GPS-ja. Če je GPS izklopljen, odgovarja samo \"off\", če je vklopljen, odgovarja z \"on\", statusom, \"fix\" in štetjem satelitiv.", + "repeater_cliHelpGpsOnOff": "Omogoči/onameni GPS način delovanja.", + "repeater_cliHelpGpsSync": "Sinhronizira čas časa ničala z gps uro.", + "repeater_cliHelpGpsSetLoc": "Nastavi položaj časa na GPS koordinate in shranjevanje preferencij.", + "repeater_cliHelpGpsAdvert": "Omogoča konfiguracijo oglasi za notranjost člana:\n- none: ne vključevati lokacije v oglasih\n- share: deliti gps lokacijo (iz SensorManager)\n- prefs: oglaševati lokacijo shranjeno v preferencah", + "repeater_cliHelpGpsAdvertSet": "Nastavi konfiguracijo oglasa na določenem mestu.", + "repeater_commandsListTitle": "Seznam ukazov", + "repeater_commandsListNote": "Opomba: za različne ukaze \"nastavi ...\" obstaja tudi ukaz \"dobi ...\".", + "repeater_general": "Općenito", + "repeater_settingsCategory": "Nastavitve", + "repeater_bridge": "Most", + "repeater_logging": "Logiranje", + "repeater_neighborsRepeaterOnly": "Sosedi (le za ponovitelja)", + "repeater_regionManagementRepeaterOnly": "Upravljanje regij (zgolj za ponovitve)", + "repeater_regionNote": "Regionske ukazi so bili uvedeni za upravljanje z regijskimi definicijami in dovolili.", + "repeater_gpsManagement": "Upravljanje GPS", + "repeater_gpsNote": "GPS ukaz je bil uveden za upravljanje z vprašanji, povezanimi z lokacijo.", + "telemetry_receivedData": "Prejeto Telemetrično podatke", + "telemetry_requestTimeout": "Zahtev telemetrije je iztekla.", + "telemetry_errorLoading": "Napaka pri obnašanju telemetrije: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "Niso na voljo podatki o telemetriji.", + "telemetry_channelTitle": "Kanal {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Baterija", + "telemetry_voltageLabel": "Napetost", + "telemetry_mcuTemperatureLabel": "MCU Temperatura", + "telemetry_temperatureLabel": "Temperatura", + "telemetry_currentLabel": "Trenutno", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Pot do paketa", + "channelPath_viewMap": "Prikaži zemljeznico", + "channelPath_otherObservedPaths": "Drugi opazovani poti", + "channelPath_repeaterHops": "Skoki ponovitelja", + "channelPath_noHopDetails": "Podrobnosti o paketu za dostavo niso navedene.", + "channelPath_messageDetails": "Podrobnosti sporočila", + "channelPath_senderLabel": "Pošiljalec", + "channelPath_timeLabel": "Čas", + "channelPath_repeatsLabel": "Ponovi", + "channelPath_pathLabel": "Pot {index}", + "channelPath_observedLabel": "Opazovani", + "channelPath_observedPathTitle": "Opazovana pot {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "Nihče ni določil lokacije.", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Neznano", + "channelPath_floodPath": "Prebivalstvo", + "channelPath_directPath": "Neposredni", + "channelPath_observedZeroOf": "0 iz {total} skokov", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} iz {total} skokov", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Potni zemljevid", + "channelPath_noRepeaterLocations": "Ni na voljo nobenih lokacij za ponovitelja za to pot.", + "channelPath_primaryPath": "Pot {index} (Glavni)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Pot", + "channelPath_observedPathHeader": "Opazovana pot", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "Niso na voljo podrobnosti o letu.", + "channelPath_unknownRepeater": "Nepoznati ponovitelj", + "listFilter_tooltip": "Filtri in vrstiči", + "listFilter_sortBy": "Sortiraj po", + "listFilter_latestMessages": "Najnovejše sporočilo", + "listFilter_heardRecently": "Nedavno slišan", + "listFilter_az": "A-Z", + "listFilter_filters": "Filtri", + "listFilter_all": "Vse", + "listFilter_users": "Uporabniki", + "listFilter_repeaters": "Ponovitve", + "listFilter_roomServers": "Smeti za prostore", + "listFilter_unreadOnly": "Nezbrani samo", + "listFilter_newGroup": "Nova skupina" +} diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb new file mode 100644 index 0000000..866e438 --- /dev/null +++ b/lib/l10n/app_sv.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "sv", + "appTitle": "MeshCore Open", + "nav_contacts": "Kontakter", + "nav_channels": "Kanaler", + "nav_map": "Karta", + "common_cancel": "Avbryt", + "common_connect": "Anslut", + "common_unknownDevice": "Okänd enhet", + "common_save": "Spara", + "common_delete": "Radera", + "common_close": "Stänga", + "common_edit": "Redigera", + "common_add": "Lägg till", + "common_settings": "Inställningar", + "common_disconnect": "Koppla från", + "common_connected": "Ansluten", + "common_disconnected": "Ansluten", + "common_create": "Skapa", + "common_continue": "Fortsätt", + "common_share": "Dela", + "common_copy": "Kopiera", + "common_retry": "Försök igen", + "common_hide": "Dölj", + "common_remove": "Ta bort", + "common_enable": "Aktivera", + "common_disable": "Inaktivera", + "common_reboot": "Start om", + "common_loading": "Laddar...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "Söker efter enheter...", + "scanner_connecting": "Anslutning...", + "scanner_disconnecting": "Anslutning bryts...", + "scanner_notConnected": "Inte ansluten", + "scanner_connectedTo": "Ansluten till {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "Söker efter MeshCore-enheter...", + "scanner_tapToScan": "Tryck Skanna för att hitta MeshCore-enheter", + "scanner_connectionFailed": "Anslutning misslyckades: {error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "Stoppa", + "scanner_scan": "Skanna", + "device_quickSwitch": "Snabb växling", + "device_meshcore": "MeshCore", + "settings_title": "Inställningar", + "settings_deviceInfo": "Enhetens information", + "settings_appSettings": "Appinställningar", + "settings_appSettingsSubtitle": "Meddelanden, notiser och kartinställningar", + "settings_nodeSettings": "Nodinställningar", + "settings_nodeName": "Nodnamn", + "settings_nodeNameNotSet": "Inte angivet", + "settings_nodeNameHint": "Ange nodnamn", + "settings_nodeNameUpdated": "Namn uppdaterat", + "settings_radioSettings": "Radioinställningar", + "settings_radioSettingsSubtitle": "Frekvens, effekt, spridningsfaktor", + "settings_radioSettingsUpdated": "Radioinställningarna har uppdaterats", + "settings_location": "Plats", + "settings_locationSubtitle": "GPS koordinater", + "settings_locationUpdated": "Plats uppdaterad", + "settings_locationBothRequired": "Ange både latitud och longitud.", + "settings_locationInvalid": "Ogiltig latitud eller longitud.", + "settings_latitude": "Latitud", + "settings_longitude": "Längdgrad", + "settings_privacyMode": "Privatläge", + "settings_privacyModeSubtitle": "Dölj namn/plats i annonser", + "settings_privacyModeToggle": "Aktivera privatläge för att dölja ditt namn och din plats i annonser.", + "settings_privacyModeEnabled": "Privatläget är aktiverat", + "settings_privacyModeDisabled": "Privatläge är avstängt", + "settings_actions": "Åtgärder", + "settings_sendAdvertisement": "Skicka Annons", + "settings_sendAdvertisementSubtitle": "Sändning finns nu", + "settings_advertisementSent": "Annons skickad", + "settings_syncTime": "Synkroniseringstid", + "settings_syncTimeSubtitle": "Ställ enheten till telefonens tid", + "settings_timeSynchronized": "Tidssynkroniserat", + "settings_refreshContacts": "Uppdatera Kontakter", + "settings_refreshContactsSubtitle": "Ladda om kontaktlistan från enheten", + "settings_rebootDevice": "Starta om enheten", + "settings_rebootDeviceSubtitle": "Starta MeshCore-enheten", + "settings_rebootDeviceConfirm": "Är du säker på att du vill starta om enheten? Du kommer att bli avkopplad.", + "settings_debug": "Felsök", + "settings_bleDebugLog": "BLE-felsökning", + "settings_bleDebugLogSubtitle": "BLE-kommandon, svar och rådata", + "settings_appDebugLog": "Appfelsökning", + "settings_appDebugLogSubtitle": "Applikations felsökningsmeddelanden", + "settings_about": "Om", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "2024 MeshCore Öppen Källkodsprojekt", + "settings_aboutDescription": "En öppen källkods Flutter-klient för MeshCore LoRa meshnätverksenheter.", + "settings_infoName": "Namn", + "settings_infoId": "ID", + "settings_infoStatus": "Status", + "settings_infoBattery": "Batteri", + "settings_infoPublicKey": "Allmänt nyckel", + "settings_infoContactsCount": "Kontakterantal", + "settings_infoChannelCount": "Kanalantal", + "settings_presets": "Fördefinierade inställningar", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "Frekvens (MHz)", + "settings_frequencyHelper": "300,0 - 2500,0", + "settings_frequencyInvalid": "Ogiltig frekvens (300-2500 MHz)", + "settings_bandwidth": "Bandbredd", + "settings_spreadingFactor": "Spreadingfaktor", + "settings_codingRate": "Kodningsgrad", + "settings_txPower": "TX-effekt (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "Ogiltig TX-effekt (0-22 dBm)", + "settings_longRange": "Lång räckvidd", + "settings_fastSpeed": "Snabb hastighet", + "settings_error": "Fel: {message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "Appinställningar", + "appSettings_appearance": "Utseende", + "appSettings_theme": "Tema", + "appSettings_themeSystem": "Systemstandard", + "appSettings_themeLight": "Ljus", + "appSettings_themeDark": "Mörk", + "appSettings_language": "Språk", + "appSettings_languageSystem": "Systemstandard", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "Meddelanden", + "appSettings_enableNotifications": "Aktivera Notifikationer", + "appSettings_enableNotificationsSubtitle": "Ta emot notiser för meddelanden och reklam", + "appSettings_notificationPermissionDenied": "Tillåtelse för notifikationer nekad", + "appSettings_notificationsEnabled": "Notifikationer aktiverade", + "appSettings_notificationsDisabled": "Meddelanden är avstängda", + "appSettings_messageNotifications": "Meddelandekrav", + "appSettings_messageNotificationsSubtitle": "Visa notis när nya meddelanden tas emot", + "appSettings_channelMessageNotifications": "Kanalmeddelandena", + "appSettings_channelMessageNotificationsSubtitle": "Visa notis när meddelanden i kanal mottas", + "appSettings_advertisementNotifications": "Annonsmeddelanden", + "appSettings_advertisementNotificationsSubtitle": "Visa notis när nya noder upptäcks", + "appSettings_messaging": "Meddelanden", + "appSettings_clearPathOnMaxRetry": "Rensa Vägen på Max Försök", + "appSettings_clearPathOnMaxRetrySubtitle": "Återställ kontaktväg efter 5 misslyckade försök att skicka", + "appSettings_pathsWillBeCleared": "Sökvägar kommer att tömmas efter 5 misslyckade försök.", + "appSettings_pathsWillNotBeCleared": "Sökvägar kommer inte att rensas automatiskt.", + "appSettings_autoRouteRotation": "Automatisk Rutväxling", + "appSettings_autoRouteRotationSubtitle": "Blixtra mellan bästa vägar och flödesläge", + "appSettings_autoRouteRotationEnabled": "Automatisk ruttrotation är aktiverad", + "appSettings_autoRouteRotationDisabled": "Automatisk ruttrotation är avstängd", + "appSettings_battery": "Batteri", + "appSettings_batteryChemistry": "Batterikemi", + "appSettings_batteryChemistryPerDevice": "Ställ in per enhet ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "Anslut till en enhet för att välja", + "appSettings_batteryNmc": "18650 NMC (3.0-4.2V)", + "appSettings_batteryLifepo4": "LiFePO4 (2,6–3,65V)", + "appSettings_batteryLipo": "LiPo (3.0-4.2V)", + "appSettings_mapDisplay": "Kartvisning", + "appSettings_showRepeaters": "Visa återuppslag", + "appSettings_showRepeatersSubtitle": "Visa återspelsnoder på kartan", + "appSettings_showChatNodes": "Visa Chattnoder", + "appSettings_showChatNodesSubtitle": "Visa chattnoder på kartan", + "appSettings_showOtherNodes": "Visa andra noder", + "appSettings_showOtherNodesSubtitle": "Visa andra nodtyper på kartan", + "appSettings_timeFilter": "Tidsfilter", + "appSettings_timeFilterShowAll": "Visa alla noder", + "appSettings_timeFilterShowLast": "Visa noder från de senaste {hours} timmarna", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "Karttid Filter", + "appSettings_showNodesDiscoveredWithin": "Visa noder som upptäckts inom:", + "appSettings_allTime": "Totalen", + "appSettings_lastHour": "Sista timmen", + "appSettings_last6Hours": "De senaste 6 timmarna", + "appSettings_last24Hours": "De senaste 24 timmarna", + "appSettings_lastWeek": "Förra veckan", + "appSettings_offlineMapCache": "Offline Kartcache", + "appSettings_noAreaSelected": "Ingen area markerad", + "appSettings_areaSelectedZoom": "Område markerat (zoom {minZoom}-{maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "Felsök", + "appSettings_appDebugLogging": "App-felsökning och loggning", + "appSettings_appDebugLoggingSubtitle": "Logga appens felsökningsmeddelanden för felsökning", + "appSettings_appDebugLoggingEnabled": "App felsökning loggning aktiverad", + "appSettings_appDebugLoggingDisabled": "App felsökning är avstängd", + "contacts_title": "Kontakter", + "contacts_noContacts": "Inga kontakter ännu", + "contacts_contactsWillAppear": "Kontakter kommer att visas när enheter annonserar.", + "contacts_searchContacts": "Sök kontakter...", + "contacts_noUnreadContacts": "Inga oinlästa kontakter", + "contacts_noContactsFound": "Inga kontakter eller grupper hittades.", + "contacts_deleteContact": "Ta bort Kontakt", + "contacts_removeConfirm": "Ta bort {contactName} från kontakter?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "Hantera Upprepare", + "contacts_roomLogin": "Rum Inloggning", + "contacts_openChat": "Öppna Chatt", + "contacts_editGroup": "Redigera Grupp", + "contacts_deleteGroup": "Ta bort Grupp", + "contacts_deleteGroupConfirm": "Ta bort {groupName}?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "Ny grupp", + "contacts_groupName": "Gruppnamn", + "contacts_groupNameRequired": "Gruppnamnet är obligatoriskt", + "contacts_groupAlreadyExists": "Gruppen \"{name}\" finns redan.", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "Filtrera kontakter...", + "contacts_noContactsMatchFilter": "Inga kontakter matchar ditt filter", + "contacts_noMembers": "Inga medlemmar", + "contacts_lastSeenNow": "Senast synlig nu", + "contacts_lastSeenMinsAgo": "Senast sedd {minutes} min sedan", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "Senast sedd för 1 timme sedan", + "contacts_lastSeenHoursAgo": "Senast sedd {hours} timmar sedan", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "Senast sedd för 1 dag sedan", + "contacts_lastSeenDaysAgo": "Senast synlig {days} dagar sedan", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "Kanaler", + "channels_noChannelsConfigured": "Inga kanaler konfigurerade", + "channels_addPublicChannel": "Lägg till publik kanal", + "channels_searchChannels": "Sök kanaler...", + "channels_noChannelsFound": "Inga kanaler hittades", + "channels_channelIndex": "Kanal {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "Hashtagkanal", + "channels_public": "Offentligt", + "channels_private": "Privat", + "channels_publicChannel": "Allmänt kanal", + "channels_privateChannel": "Privat kanal", + "channels_editChannel": "Redigera kanal", + "channels_deleteChannel": "Ta bort kanal", + "channels_deleteChannelConfirm": "Radera \"{name}\"? Detta kan inte ångras.", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "Kanalen \"{name}\" raderad", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "Lägg till kanal", + "channels_channelIndexLabel": "Kanalindex", + "channels_channelName": "Kanalnamn", + "channels_usePublicChannel": "Använd Publikkanal", + "channels_standardPublicPsk": "Standard allmän PSK", + "channels_pskHex": "PSK (Hex)", + "channels_generateRandomPsk": "Generera slumpmässig PSK", + "channels_enterChannelName": "Ange en kanalnamn", + "channels_pskMustBe32Hex": "PSK måste vara 32 hexadecimala tecken", + "channels_channelAdded": "Kanalen \"{name}\" har lagts till", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "Redigera Kanal {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "SMAZ-komprimering", + "channels_channelUpdated": "Kanalen \"{name}\" har uppdaterats", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "Allmänt kanal tillagd", + "channels_sortBy": "Sortera efter", + "channels_sortManual": "Manuell", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "Senaste meddelanden", + "channels_sortUnread": "Oläst", + "chat_noMessages": "Inga meddelanden ännu", + "chat_sendMessageToStart": "Skicka ett meddelande för att komma igång", + "chat_originalMessageNotFound": "Originalt meddelande hittades inte", + "chat_replyingTo": "Svara till {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "Svara till {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "Plats", + "chat_sendMessageTo": "Skicka ett meddelande till {contactName}", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "Skriv ett meddelande...", + "chat_messageTooLong": "Meddelandet är för långt (max {maxBytes} byte).", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "Meddelandet kopierades", + "chat_messageDeleted": "Meddelandet raderat", + "chat_retryingMessage": "Försöker igen", + "chat_retryCount": "Försök igen {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "Skicka GIF", + "chat_reply": "Svara", + "chat_addReaction": "Lägg till reaktion", + "chat_me": "Mig", + "emojiCategorySmileys": "Emojis", + "emojiCategoryGestures": "Gestikuleringar", + "emojiCategoryHearts": "Hjärtan", + "emojiCategoryObjects": "Objekt", + "gifPicker_title": "Välj en GIF", + "gifPicker_searchHint": "Sök GIF:ar...", + "gifPicker_poweredBy": "Drivet av GIPHY", + "gifPicker_noGifsFound": "Inga GIF-filer hittades", + "gifPicker_failedLoad": "Kunde inte ladda GIF-filer", + "gifPicker_failedSearch": "Sökningen misslyckades.", + "gifPicker_noInternet": "Ingen internetanslutning", + "debugLog_appTitle": "Appfelsökning", + "debugLog_bleTitle": "BLE-felsökning", + "debugLog_copyLog": "Kopiera logg", + "debugLog_clearLog": "Rensa logg", + "debugLog_copied": "Felsökningslogg kopierad", + "debugLog_bleCopied": "BLE-logg kopierad", + "debugLog_noEntries": "Inga felsökningsloggar ännu", + "debugLog_enableInSettings": "Aktivera appens felsökningsloggning i inställningarna", + "debugLog_frames": "Rammar", + "debugLog_rawLogRx": "Rå Log-RX", + "debugLog_noBleActivity": "Ingen BLE-aktivitet ännu", + "debugFrame_length": "Ramstorlek: {count} byte", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "Kommando: 0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "Textmeddelandefält:", + "debugFrame_destinationPubKey": "– Destination PubKey: {pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- Tidsstämpel: {timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- Flaggor: 0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- Texttyp: {type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "Enkel", + "debugFrame_text": "- Text: \"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "Hexdump:", + "chat_pathManagement": "Stigarhantering", + "chat_routingMode": "Ruttläge", + "chat_autoUseSavedPath": "Automatisk (använd sparad sökväg)", + "chat_forceFloodMode": "Tvinga Översvämningsläge", + "chat_recentAckPaths": "Nyligen Ack-vägar (tryck för att använda):", + "chat_pathHistoryFull": "Historisk sökväg är full. Ta bort poster för att lägga till nya.", + "chat_hopSingular": "hoppa", + "chat_hopPlural": "hoppar", + "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "framgångar", + "chat_removePath": "Ta bort sökväg", + "chat_noPathHistoryYet": "Ingen historik ännu.\nSkicka ett meddelande för att upptäcka spår.", + "chat_pathActions": "Stigar:", + "chat_setCustomPath": "Ange anpassad sökväg", + "chat_setCustomPathSubtitle": "Ange ruttväg manuellt", + "chat_clearPath": "Rensa Vägen", + "chat_clearPathSubtitle": "Tvinga fram omstart vid nästa sändning", + "chat_pathCleared": "Routen är nu fri. Nästa meddelande kommer att upptäcka rutten igen.", + "chat_floodModeSubtitle": "Använd routningsomkopplaren i appraden", + "chat_floodModeEnabled": "Översvämningsläge aktiverat. Stäng av via ruttikonen i appraden.", + "chat_fullPath": "Fullständig sökväg", + "chat_pathDetailsNotAvailable": "Stigaruppgifterna är ännu inte tillgängliga. Försök att skicka ett meddelande för att uppdatera.", + "chat_pathSetHops": "Sökväg inställd: {hopCount} {hopCount, plural, =1{hopp} other{hoppar}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "Sparat lokalt. Anslut för att synkronisera.", + "chat_pathDeviceConfirmed": "Enheten bekräftad.", + "chat_pathDeviceNotConfirmed": "Enheten har inte bekräftats ännu.", + "chat_type": "Skriv", + "chat_path": "Sökväg", + "chat_publicKey": "Allmänt nyckel", + "chat_compressOutgoingMessages": "Kryptera utgående meddelanden", + "chat_floodForced": "Översvämning (tvingad)", + "chat_directForced": "Direkt (tvingad)", + "chat_hopsForced": "{count} hopp (tvingat)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "Översvämning (auto)", + "chat_direct": "Direkt", + "chat_poiShared": "Delad POI", + "chat_unread": "Olästa: {count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "Nodkarta", + "map_noNodesWithLocation": "Inga noder med platsinformation", + "map_nodesNeedGps": "Noder måste dela sina GPS-koordinater\nför att visas på kartan", + "map_nodesCount": "Noder: {count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "Pinnar: {count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "Chat", + "map_repeater": "Återuppspelare", + "map_room": "Rum", + "map_sensor": "Sensor", + "map_pinDm": "Lås (DM)", + "map_pinPrivate": "Lås (Privat)", + "map_pinPublic": "Anslå (Offentligt)", + "map_lastSeen": "Senast sedd", + "map_disconnectConfirm": "Är du säker på att du vill koppla från enheten?", + "map_from": "Från", + "map_source": "Källa", + "map_flags": "Flaggor", + "map_shareMarkerHere": "Dela markeringen här", + "map_pinLabel": "Fästetikett", + "map_label": "Etikett", + "map_pointOfInterest": "Plats av intresse", + "map_sendToContact": "Skicka till kontakt", + "map_sendToChannel": "Skicka till kanal", + "map_noChannelsAvailable": "Inga kanaler tillgängliga", + "map_publicLocationShare": "Dela offentlig plats", + "map_publicLocationShareConfirm": "Du håller på att dela en plats i {channelLabel}. Denna kanal är offentlig och alla med PSK kan se den.", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "Anslut till en enhet för att dela markörer", + "map_filterNodes": "Filtrera noder", + "map_nodeTypes": "Nodtyper", + "map_chatNodes": "Chatnoder", + "map_repeaters": "Upprepare", + "map_otherNodes": "Andra noder", + "map_keyPrefix": "Nyckelprefix", + "map_filterByKeyPrefix": "Filtrera efter nyckelprefix", + "map_publicKeyPrefix": "Allmänt nyckelprästegenskap", + "map_markers": "Markörer", + "map_showSharedMarkers": "Visa delade markörer", + "map_lastSeenTime": "Senaste Visats Tid", + "map_sharedPin": "Delad PIN", + "map_joinRoom": "Gå med i rum", + "map_manageRepeater": "Hantera Upprepare", + "mapCache_title": "Offline Kartcache", + "mapCache_selectAreaFirst": "Välj ett område att cachera först", + "mapCache_noTilesToDownload": "Inga kuber att ladda ner för detta område", + "mapCache_downloadTilesTitle": "Ladda ner klick", + "mapCache_downloadTilesPrompt": "Ladda ner {count} kuber för offlineanvändning?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "Ladda ner", + "mapCache_cachedTiles": "Cache {count} kuber", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "Cachelagda {downloaded} klickark ({failed} misslyckades)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "Rensa offline-cache", + "mapCache_clearOfflineCachePrompt": "Ta bort alla cachemapplaner?", + "mapCache_offlineCacheCleared": "Offline-cache rensad", + "mapCache_noAreaSelected": "Ingen area markerad", + "mapCache_cacheArea": "Cacheområde", + "mapCache_useCurrentView": "Använd Aktuell Visning", + "mapCache_zoomRange": "Zoombegränsning", + "mapCache_estimatedTiles": "Uppskattat antal klick: {count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "Ladda ner {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "Ladda ner klick", + "mapCache_clearCacheButton": "Rensa Cache", + "mapCache_failedDownloads": "Misslyckade nedladdningar: {count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "Precis nu", + "time_minutesAgo": "{minutes} min sedan", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours} timmar sedan", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} dagar sedan", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "timme", + "time_hours": "timmar", + "time_day": "dag", + "time_days": "dagar", + "time_week": "vecka", + "time_weeks": "veckor", + "time_month": "månad", + "time_months": "månader", + "time_minutes": "minuter", + "time_allTime": "Alla tider", + "dialog_disconnect": "Koppla från", + "dialog_disconnectConfirm": "Är du säker på att du vill koppla från enheten?", + "login_repeaterLogin": "Återuppta Inloggning", + "login_roomLogin": "Rum Inloggning", + "login_password": "Lösenord", + "login_enterPassword": "Ange lösenord", + "login_savePassword": "Spara lösenord", + "login_savePasswordSubtitle": "Lösenord kommer att lagras säkert på enheten.", + "login_repeaterDescription": "Ange återuppspelarens lösenord för att komma åt inställningar och status.", + "login_roomDescription": "Ange rummets lösenord för att komma åt inställningar och status.", + "login_routing": "Ruttning", + "login_routingMode": "Ruttläge", + "login_autoUseSavedPath": "Automatisk (använd sparad sökväg)", + "login_forceFloodMode": "Tvinga Översvämningsläge", + "login_managePaths": "Hantera Sökvägar", + "login_login": "Logga in", + "login_attempt": "Försök {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "Inloggning misslyckades: {error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "Ladda om", + "common_clear": "Rensa", + "path_currentPath": "Nuvarande sökväg: {path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "Använda {count} {count, plural, =1{hop} other{hops}} sökväg", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "Ange anpassad sökväg", + "path_currentPathLabel": "Nuvarande sökväg", + "path_hexPrefixInstructions": "Ange 2-tecknets hex-prefett för varje hopp, åtskilda med komma.", + "path_hexPrefixExample": "Exempel: A1,F2,3C (varje nod använder det första bytet av sitt publika nyckel)", + "path_labelHexPrefixes": "Hexprefixer", + "path_helperMaxHops": "Max 64 hopp. Varje prefix är 2 hex-tecken (1 byte)", + "path_selectFromContacts": "Välj istället från kontakter:", + "path_noRepeatersFound": "Inga återuppspelare eller rumsservrar hittades.", + "path_customPathsRequire": "Anpassade sökvägar kräver mellansteg som kan vidarebefordra meddelanden.", + "path_invalidHexPrefixes": "Ogiltiga hex-prefikser: {prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "Sökvägen är för lång. Max 64 hopp tillåtna.", + "path_setPath": "Ange Sökväg", + "repeater_management": "Återuppspelarens Hantering", + "repeater_managementTools": "Administrationsverktyg", + "repeater_status": "Status", + "repeater_statusSubtitle": "Visa återspolningsstatus, statistik och grannar", + "repeater_telemetry": "Telemetry", + "repeater_telemetrySubtitle": "Visa telemetri för sensorer och systemstatistik", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "Skicka kommandon till repetitorn", + "repeater_settings": "Inställningar", + "repeater_settingsSubtitle": "Konfigurera återspolarparametrar", + "repeater_statusTitle": "Återspelsstatus", + "repeater_routingMode": "Ruttläge", + "repeater_autoUseSavedPath": "Automatisk (använd sparad sökväg)", + "repeater_forceFloodMode": "Tvinga Översvämningsläge", + "repeater_pathManagement": "Stigarhantering", + "repeater_refresh": "Uppdatera", + "repeater_statusRequestTimeout": "Statusförfrågan gick inte att hämta.", + "repeater_errorLoadingStatus": "Fel vid inläsning av status: {error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "Systeminformation", + "repeater_battery": "Batteri", + "repeater_clockAtLogin": "Klocka (vid inloggning)", + "repeater_uptime": "Tillgänglighet", + "repeater_queueLength": "Köans längd", + "repeater_debugFlags": "Felsökningsflaggor", + "repeater_radioStatistics": "Radiostatistik", + "repeater_lastRssi": "Senaste RSSI", + "repeater_lastSnr": "Sista SNR", + "repeater_noiseFloor": "Ljudnivå", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "Paketstatistik", + "repeater_sent": "Skickat", + "repeater_received": "Mottaget", + "repeater_duplicates": "Dubbletter", + "repeater_daysHoursMinsSecs": "{days} dagar {hours} timmar {minutes} minuter {seconds} sekunder", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "Totalt: {total}, Översvämning: {flood}, Direkt: {direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "Totalt: {total}, Översvämning: {flood}, Direkt: {direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "Översvämning: {flood}, Direkt: {direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "Totalt: {total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "Återuppspelarens Inställningar", + "repeater_basicSettings": "Grundinställningar", + "repeater_repeaterName": "Upprepare Namn", + "repeater_repeaterNameHelper": "Visa namn för denna återupprepare", + "repeater_adminPassword": "Adminlösenord", + "repeater_adminPasswordHelper": "Fullständig åtkomstlösenord", + "repeater_guestPassword": "Gästlösenhet", + "repeater_guestPasswordHelper": "Läs-skyddspassord", + "repeater_radioSettings": "Radioinställningar", + "repeater_frequencyMhz": "Frekvens (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Effekt", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "Bandbredd", + "repeater_spreadingFactor": "Spreadingfaktor", + "repeater_codingRate": "Kodningsgrad", + "repeater_locationSettings": "Platsinställningar", + "repeater_latitude": "Latitud", + "repeater_latitudeHelper": "Decimalgrader (t.ex. 37.7749)", + "repeater_longitude": "Längdgrad", + "repeater_longitudeHelper": "Decimalgrader (t.ex. -122.4194)", + "repeater_features": "Funktioner", + "repeater_packetForwarding": "Paketväxling", + "repeater_packetForwardingSubtitle": "Aktivera återuppspelaren för att vidarebefordra paket", + "repeater_guestAccess": "Gäståtkomst", + "repeater_guestAccessSubtitle": "Tillåt läsbehörigheter för gäster.", + "repeater_privacyMode": "Privatläge", + "repeater_privacyModeSubtitle": "Dölj namn/plats i annonser", + "repeater_advertisementSettings": "Annonsinställningar", + "repeater_localAdvertInterval": "Lokalt Annonsintervall", + "repeater_localAdvertIntervalMinutes": "{minutes} minuter", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "Översvämnadsannonsens tidsintervall", + "repeater_floodAdvertIntervalHours": "{hours} timmar", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "Krypterad Annonsintervall", + "repeater_dangerZone": "Faraområde", + "repeater_rebootRepeater": "Starta Återuppspelaren", + "repeater_rebootRepeaterSubtitle": "Starta om repeternheten", + "repeater_rebootRepeaterConfirm": "Är du säker på att du vill starta om denna repeater?", + "repeater_regenerateIdentityKey": "Generera Identitetsknyckel", + "repeater_regenerateIdentityKeySubtitle": "Generera ny publik/privat nyckelpar", + "repeater_regenerateIdentityKeyConfirm": "Detta kommer att generera en ny identitet för återspelaren. Fortsätta?", + "repeater_eraseFileSystem": "Radera Filsystem", + "repeater_eraseFileSystemSubtitle": "Formatera återspelsfilsystemet", + "repeater_eraseFileSystemConfirm": "VARNING: Detta kommer att radera all data på repeatern. Detta kan inte ångras!", + "repeater_eraseSerialOnly": "Rensa är endast tillgängligt via seriell konsol.", + "repeater_commandSent": "Kommandot skickades: {command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "Fel vid skickande av kommando: {error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "Bekräfta", + "repeater_settingsSaved": "Inställningarna sparades framgångsrikt.", + "repeater_errorSavingSettings": "Fel vid sparande av inställningar: {error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "Återställ Grundläggande Inställningar", + "repeater_refreshRadioSettings": "Återställ Radiosinställningar", + "repeater_refreshTxPower": "Återställ TX-effekt", + "repeater_refreshLocationSettings": "Uppdatera Lokationsinställningar", + "repeater_refreshPacketForwarding": "Återställ Paketväxling", + "repeater_refreshGuestAccess": "Återställ Gäståtkomst", + "repeater_refreshPrivacyMode": "Återställ Sekretessläge", + "repeater_refreshAdvertisementSettings": "Återställ Annonsinställningar", + "repeater_refreshed": "{label} har uppdaterats", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "Fel vid uppdatering av {label}", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "Återuppspelaren CLI", + "repeater_debugNextCommand": "Felsök Nästa Kommando", + "repeater_commandHelp": "Hjälp", + "repeater_clearHistory": "Rensa Historik", + "repeater_noCommandsSent": "Inga kommandon skickats ännu", + "repeater_typeCommandOrUseQuick": "Skriv en kommando nedan eller använd snabba kommandon", + "repeater_enterCommandHint": "Ange kommando...", + "repeater_previousCommand": "Tidigare kommando", + "repeater_nextCommand": "Nästa kommando", + "repeater_enterCommandFirst": "Ange en kommando först", + "repeater_cliCommandFrameTitle": "Kommandofönster", + "repeater_cliCommandError": "Fel: {error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "Hämta namn", + "repeater_cliQuickGetRadio": "Få Radio", + "repeater_cliQuickGetTx": "Hämta TX", + "repeater_cliQuickNeighbors": "Grannar", + "repeater_cliQuickVersion": "Version", + "repeater_cliQuickAdvertise": "Annonsera", + "repeater_cliQuickClock": "Klocka", + "repeater_cliHelpAdvert": "Skickar ett annonspaket", + "repeater_cliHelpReboot": "Startar om enheten. (notera, du får kanske 'Timeout' vilket är normalt)", + "repeater_cliHelpClock": "Visar aktuell tid per enhetens klocka.", + "repeater_cliHelpPassword": "Ställer in ett nytt administratörslösenord för enheten.", + "repeater_cliHelpVersion": "Visar enhetsversion och firmwarebyggnadsdatum.", + "repeater_cliHelpClearStats": "Återställer olika statistikräknare till noll.", + "repeater_cliHelpSetAf": "Ställer in lufttidsfaktor.", + "repeater_cliHelpSetTx": "Ställer LoRa-sändningseffekten i dBm. (starta om för att tillämpa)", + "repeater_cliHelpSetRepeat": "Aktiverar eller inaktiverar återuppspelarens roll för denna nod.", + "repeater_cliHelpSetAllowReadOnly": "(Rumserver) Om 'på', så tillåts login med tomt lösenord, men kan inte Posta till rummet. (bara läsa).", + "repeater_cliHelpSetFloodMax": "Ställer in det maximala antalet hopp för inkommande översvämning (om >= max, skickas inte paketet).", + "repeater_cliHelpSetIntThresh": "Ställer Interferensgränsen (i dB). Standardvärdet är 14. Ställ in den på 0 för att inaktivera detektion av kanalinterferens.", + "repeater_cliHelpSetAgcResetInterval": "Ställer in intervallet för att återställa Auto Gain-kontrollen. Ställ in till 0 för att inaktivera.", + "repeater_cliHelpSetMultiAcks": "Aktiverar eller inaktiverar funktionen 'dubbla ACKs'.", + "repeater_cliHelpSetAdvertInterval": "Ställer in tidsintervallen i minuter för att skicka ett lokalt (utan-hopp) annonseringspaket. Ställs till 0 för att inaktivera.", + "repeater_cliHelpSetFloodAdvertInterval": "Ställer in tidsintervallen i timmar för att skicka ett flödesannonspaket. Ställ in på 0 för att inaktivera.", + "repeater_cliHelpSetGuestPassword": "Ställer in/uppdaterar gästlösenordet. (för återvändare kan gästloggar skicka \"Get Stats\"-förfrågan)", + "repeater_cliHelpSetName": "Ställer in annonstexterna namn.", + "repeater_cliHelpSetLat": "Ställer in annonskartans latitud. (decimalgrader)", + "repeater_cliHelpSetLon": "Ställer in annonskartans longitud (decimalgrader).", + "repeater_cliHelpSetRadio": "Ställer helt nya radioparametrar och sparar dem i inställningar. Kräver en \"omstart\" för att tillämpa.", + "repeater_cliHelpSetRxDelay": "Ställer (experimentell) basvärde (måste vara > 1 för effekt) för att applicera en liten fördröjning på mottagna paket, baserat på signalstyrka/poäng. Ställ in på 0 för att inaktivera.", + "repeater_cliHelpSetTxDelay": "Ställer in en faktor som multipliceras med tid på luft för en översvämningsläge-paket och med ett slumpmässigt slot-system för att fördröja dess vidarebefordran (för att minska risken för kollisioner).", + "repeater_cliHelpSetDirectTxDelay": "Samma som txdelay, men för att applicera en slumpmässig fördröjning vid vidarebefordran av direktlägespaket.", + "repeater_cliHelpSetBridgeEnabled": "Aktivera/Inaktivera brygga.", + "repeater_cliHelpSetBridgeDelay": "Ställ in fördröjning innan paket åter sänder.", + "repeater_cliHelpSetBridgeSource": "Välj om bron ska återända mottagna paket eller sända paket.", + "repeater_cliHelpSetBridgeBaud": "Ställ baudgränsen för rs232-bryggarna.", + "repeater_cliHelpSetBridgeSecret": "Ställ bro-hemlighet för espnow-broar.", + "repeater_cliHelpSetAdcMultiplier": "Ställer in anpassad faktor för att justera rapporterad batterispänning (endast stödd på utvalda kort).", + "repeater_cliHelpTempRadio": "Ställer temporära radioparametrar för det angivna antalet minuter, vilket återgår till de ursprungliga radioparametrarna efteråt. (sparar inte i inställningar).", + "repeater_cliHelpSetPerm": "Modifierar ACL. Tar bort matchande post (genom pubkey-prefiks) om \"permissions\" är noll. Lägger till ny post om pubkey-hex är full längd och inte redan finns i ACL. Uppdaterar posten genom matchande pubkey-prefiks. Tillståndsbiten varierar per firmware-roll, men de låga 2 bitarna är: 0 (Gäst), 1 (endast läsa), 2 (läs- och skrivskydd), 3 (administratör).", + "repeater_cliHelpGetBridgeType": "Får brotyperna ingen, rs232, espnow", + "repeater_cliHelpLogStart": "Starta paketloggning till filsystem.", + "repeater_cliHelpLogStop": "Stoppar paketloggning till filsystem.", + "repeater_cliHelpLogErase": "Raderar pakets loggar från filsystemet.", + "repeater_cliHelpNeighbors": "Visar en lista över andra repeaternoder som hörts via noll-hop-annonser. Varje rad är id-prefix-hex:tidsstämpel:snr-g撮-4", + "repeater_cliHelpNeighborRemove": "Tar bort det första matchande inlägget (genom pubkey-prefiks (hex)) från grannlistan.", + "repeater_cliHelpRegion": "(Serien endast) Listar alla definierade regioner och aktuella översvämningsbehörigheter.", + "repeater_cliHelpRegionLoad": "MEDDELANDE: detta är ett specialkommando med flera kommandon. Varje efterföljande kommando är ett regionsnamn (indenterat med blanksteg för att indikera en hierarkisk relation, med minst ett blanksteg). Avslutas genom att skicka en tom rad/kommando.", + "repeater_cliHelpRegionGet": "Söker efter region med given namnprefiks (eller \"\" för det globala scopet). Svarar med \"-> regionnamn (föräldernamn) 'F'\"", + "repeater_cliHelpRegionPut": "Lägger till eller uppdaterar en regionsdefinition med det angivna namnet.", + "repeater_cliHelpRegionRemove": "Tar bort en regionsdefinition med det angivna namnet. (måste matcha exakt och inte ha några barnregioner)", + "repeater_cliHelpRegionAllowf": "Ställer 'Flöde'-behörighet för det angivna området. ('' för det globala/gamla scopet)", + "repeater_cliHelpRegionDenyf": "Tar bort 'F'lood-behörigheten för det angivna området. (OBS: rekommenderas inte att använda detta i detta skede på den globala/gamla omfattningen!!).", + "repeater_cliHelpRegionHome": "Svarar med den aktuella 'hem'-regionen. (Notera att detta ännu inte har tillämpats, reserverat för framtida användning).", + "repeater_cliHelpRegionHomeSet": "Ställer in 'hemregionen'.", + "repeater_cliHelpRegionSave": "Sparar regionlistan/kartan till lagring.", + "repeater_cliHelpGps": "Visar GPS-status. Om GPS är avstängd svarar den endast med \"av\", annars svarar den med \"på\", status, fix, antal satelliter.", + "repeater_cliHelpGpsOnOff": "Aktiverar/inaktiverar GPS-strömsättningen.", + "repeater_cliHelpGpsSync": "Synkroniserar nätverks tid med GPS-klockan.", + "repeater_cliHelpGpsSetLoc": "Ställer nodens position till GPS-koordinater och sparar inställningar.", + "repeater_cliHelpGpsAdvert": "Ger platsannonskonfigurationen för noden:\n- ingen: inkludera inte plats i annonser\n- dela: dela gps-plats (från SensorManager)\n- inställningar: annonsera platsen som sparats i inställningar", + "repeater_cliHelpGpsAdvertSet": "Ställer in annonsplatskonfiguration.", + "repeater_commandsListTitle": "Inställningslista", + "repeater_commandsListNote": "OBS: för de olika \"set ...\" -kommandon finns det även ett \"get ...\" -kommando.", + "repeater_general": "Allmänt", + "repeater_settingsCategory": "Inställningar", + "repeater_bridge": "Bro", + "repeater_logging": "Logga", + "repeater_neighborsRepeaterOnly": "Grannar (Endast återspelare)", + "repeater_regionManagementRepeaterOnly": "Regionhantering (endast återuppspelare)", + "repeater_regionNote": "Regionkommandon har införts för att hantera regiondefinitioner och behörigheter.", + "repeater_gpsManagement": "GPS Hantering", + "repeater_gpsNote": "GPS-kommando har introducerats för att hantera platsrelaterade ämnen.", + "telemetry_receivedData": "Mottagen Telemetridata", + "telemetry_requestTimeout": "Telemetryförfrågan gick ut.", + "telemetry_errorLoading": "Fel vid laddning av telemetri: {error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "Inga telemetridata tillgängliga.", + "telemetry_channelTitle": "Kanal {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "Batteri", + "telemetry_voltageLabel": "Spänning", + "telemetry_mcuTemperatureLabel": "MCU Temperatur", + "telemetry_temperatureLabel": "Temperatur", + "telemetry_currentLabel": "Aktuell", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "Paketväg", + "channelPath_viewMap": "Visa karta", + "channelPath_otherObservedPaths": "Övriga observerade stigar", + "channelPath_repeaterHops": "Återupptagningssteg", + "channelPath_noHopDetails": "Detaljer för denna paket är inte angivna.", + "channelPath_messageDetails": "Meddelandets detaljer", + "channelPath_senderLabel": "Avsändare", + "channelPath_timeLabel": "Tid", + "channelPath_repeatsLabel": "Upprepa", + "channelPath_pathLabel": "Sökväg {index}", + "channelPath_observedLabel": "Observerat", + "channelPath_observedPathTitle": "Observerad bana {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "Ingen platsdata", + "channelPath_timeWithDate": "{day}/{month} kl. {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "Okänt", + "channelPath_floodPath": "Översvämning", + "channelPath_directPath": "Direkt", + "channelPath_observedZeroOf": "0 av {total} hopp", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "{observed} av {total} hopp", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "Sökvägskarta", + "channelPath_noRepeaterLocations": "Inga återupprepningsplatser finns tillgängliga för denna väg.", + "channelPath_primaryPath": "Sökväg {index} (Primär)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "Sökväg", + "channelPath_observedPathHeader": "Observerad Sökväg", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "Inga hoppdetaljer finns tillgängliga för detta paket.", + "channelPath_unknownRepeater": "Okänt Upprepare", + "listFilter_tooltip": "Filtrera och sortera", + "listFilter_sortBy": "Sortera efter", + "listFilter_latestMessages": "Senaste meddelanden", + "listFilter_heardRecently": "Hörts nyligen", + "listFilter_az": "A-Z", + "listFilter_filters": "Filteralternativ", + "listFilter_all": "Alla", + "listFilter_users": "Användare", + "listFilter_repeaters": "Upprepare", + "listFilter_roomServers": "Rumservrar", + "listFilter_unreadOnly": "Endast oinlästa", + "listFilter_newGroup": "Ny grupp" +} diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb new file mode 100644 index 0000000..f1349e8 --- /dev/null +++ b/lib/l10n/app_zh.arb @@ -0,0 +1,1339 @@ +{ + "@@locale": "zh", + "appTitle": "MeshCore Open", + "nav_contacts": "联系人", + "nav_channels": "频道", + "nav_map": "地图", + "common_cancel": "取消", + "common_connect": "连接", + "common_unknownDevice": "未知设备", + "common_save": "保存", + "common_delete": "删除", + "common_close": "关闭", + "common_edit": "编辑", + "common_add": "添加", + "common_settings": "设置", + "common_disconnect": "断开", + "common_connected": "已连接", + "common_disconnected": "断开", + "common_create": "创建", + "common_continue": "继续", + "common_share": "分享", + "common_copy": "复制", + "common_retry": "重试", + "common_hide": "隐藏", + "common_remove": "删除", + "common_enable": "启用", + "common_disable": "禁用", + "common_reboot": "重启", + "common_loading": "正在加载...", + "common_notAvailable": "—", + "common_voltageValue": "{volts} V", + "@common_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "common_percentValue": "{percent}%", + "@common_percentValue": { + "placeholders": { + "percent": { + "type": "int" + } + } + }, + "scanner_title": "MeshCore Open", + "scanner_scanning": "扫描设备…", + "scanner_connecting": "连接中...", + "scanner_disconnecting": "断开中...", + "scanner_notConnected": "未连接", + "scanner_connectedTo": "已连接至 {deviceName}", + "@scanner_connectedTo": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "scanner_searchingDevices": "搜索 MeshCore 设备...", + "scanner_tapToScan": "点击扫描以查找MeshCore设备", + "scanner_connectionFailed": "连接失败:{error}", + "@scanner_connectionFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "scanner_stop": "停止", + "scanner_scan": "扫描", + "device_quickSwitch": "快速切换", + "device_meshcore": "MeshCore", + "settings_title": "设置", + "settings_deviceInfo": "设备信息", + "settings_appSettings": "应用设置", + "settings_appSettingsSubtitle": "通知、消息和地图偏好", + "settings_nodeSettings": "节点设置", + "settings_nodeName": "节点名称", + "settings_nodeNameNotSet": "未设置", + "settings_nodeNameHint": "请输入节点名称", + "settings_nodeNameUpdated": "姓名已更新", + "settings_radioSettings": "无线设置", + "settings_radioSettingsSubtitle": "频率,功率,扩展因子", + "settings_radioSettingsUpdated": "射频设置已更新", + "settings_location": "位置", + "settings_locationSubtitle": "GPS坐标", + "settings_locationUpdated": "位置已更新", + "settings_locationBothRequired": "请输入纬度和经度。", + "settings_locationInvalid": "无效的纬度或经度。", + "settings_latitude": "纬度", + "settings_longitude": "经度", + "settings_privacyMode": "隐私模式", + "settings_privacyModeSubtitle": "隐藏在广告中的姓名/位置", + "settings_privacyModeToggle": "开启隐私模式以隐藏您的姓名和位置在广告中的显示。", + "settings_privacyModeEnabled": "隐私模式已启用", + "settings_privacyModeDisabled": "隐私模式已禁用", + "settings_actions": "操作", + "settings_sendAdvertisement": "发送广告", + "settings_sendAdvertisementSubtitle": "现在已广播", + "settings_advertisementSent": "广告已发送", + "settings_syncTime": "同步时间", + "settings_syncTimeSubtitle": "将设备时钟设置为手机时间", + "settings_timeSynchronized": "时间同步", + "settings_refreshContacts": "刷新联系人", + "settings_refreshContactsSubtitle": "从设备重新加载联系人列表", + "settings_rebootDevice": "重启设备", + "settings_rebootDeviceSubtitle": "重启 MeshCore 设备", + "settings_rebootDeviceConfirm": "您确定要重启设备吗?您将会断开连接。", + "settings_debug": "调试", + "settings_bleDebugLog": "蓝牙调试日志", + "settings_bleDebugLogSubtitle": "蓝牙命令、响应和原始数据", + "settings_appDebugLog": "应用调试日志", + "settings_appDebugLogSubtitle": "应用调试消息", + "settings_about": "关于", + "settings_aboutVersion": "MeshCore Open v{version}", + "@settings_aboutVersion": { + "placeholders": { + "version": { + "type": "String" + } + } + }, + "settings_aboutLegalese": "2024 MeshCore 开放源代码项目", + "settings_aboutDescription": "一个开源的 Flutter 客户端,用于 MeshCore LoRa 网状网络设备。", + "settings_infoName": "姓名", + "settings_infoId": "ID", + "settings_infoStatus": "状态", + "settings_infoBattery": "电池", + "settings_infoPublicKey": "公钥", + "settings_infoContactsCount": "联系人数量", + "settings_infoChannelCount": "频道数量", + "settings_presets": "预设", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", + "settings_frequency": "频率 (MHz)", + "settings_frequencyHelper": "300.0 - 2500.0", + "settings_frequencyInvalid": "无效频率 (300-2500 MHz)", + "settings_bandwidth": "带宽", + "settings_spreadingFactor": "扩散因子", + "settings_codingRate": "编码速率", + "settings_txPower": "TX Power (dBm)", + "settings_txPowerHelper": "0 - 22", + "settings_txPowerInvalid": "无效的 TX 电功率 (0-22 dBm)", + "settings_longRange": "远距离", + "settings_fastSpeed": "快速速度", + "settings_error": "错误:{message}", + "@settings_error": { + "placeholders": { + "message": { + "type": "String" + } + } + }, + "appSettings_title": "应用设置", + "appSettings_appearance": "外观", + "appSettings_theme": "主题", + "appSettings_themeSystem": "系统默认", + "appSettings_themeLight": "光", + "appSettings_themeDark": "深色", + "appSettings_language": "语言", + "appSettings_languageSystem": "系统默认", + "appSettings_languageEn": "English", + "appSettings_languageFr": "Français", + "appSettings_languageEs": "Español", + "appSettings_languageDe": "Deutsch", + "appSettings_languagePl": "Polski", + "appSettings_languageSl": "Slovenščina", + "appSettings_languagePt": "Português", + "appSettings_languageIt": "Italiano", + "appSettings_languageZh": "中文", + "appSettings_languageSv": "Svenska", + "appSettings_languageNl": "Nederlands", + "appSettings_languageSk": "Slovenčina", + "appSettings_languageBg": "Български", + "appSettings_notifications": "通知", + "appSettings_enableNotifications": "启用通知", + "appSettings_enableNotificationsSubtitle": "接收消息和广告的通知", + "appSettings_notificationPermissionDenied": "通知权限被拒绝", + "appSettings_notificationsEnabled": "通知已启用", + "appSettings_notificationsDisabled": "通知已关闭", + "appSettings_messageNotifications": "消息通知", + "appSettings_messageNotificationsSubtitle": "显示收到新消息时的通知", + "appSettings_channelMessageNotifications": "频道消息通知", + "appSettings_channelMessageNotificationsSubtitle": "显示接收频道消息时的通知", + "appSettings_advertisementNotifications": "广告通知", + "appSettings_advertisementNotificationsSubtitle": "显示当新节点被发现时通知", + "appSettings_messaging": "消息", + "appSettings_clearPathOnMaxRetry": "清除最大重试路径", + "appSettings_clearPathOnMaxRetrySubtitle": "重置联系人路径,在5次发送失败尝试后", + "appSettings_pathsWillBeCleared": "路径将在5次失败重试后清除", + "appSettings_pathsWillNotBeCleared": "路径不会自动清理", + "appSettings_autoRouteRotation": "自动路径旋转", + "appSettings_autoRouteRotationSubtitle": "在最佳路径和洪水模式之间切换", + "appSettings_autoRouteRotationEnabled": "自动路径轮换已启用", + "appSettings_autoRouteRotationDisabled": "自动路径轮换已禁用", + "appSettings_battery": "电池", + "appSettings_batteryChemistry": "电池化学", + "appSettings_batteryChemistryPerDevice": "设置每个设备 ({deviceName})", + "@appSettings_batteryChemistryPerDevice": { + "placeholders": { + "deviceName": { + "type": "String" + } + } + }, + "appSettings_batteryChemistryConnectFirst": "连接设备以选择", + "appSettings_batteryNmc": "18650 NMC (3.0-4.2V)", + "appSettings_batteryLifepo4": "磷酸铁锂 (2.6-3.65V)", + "appSettings_batteryLipo": "LiPo (3.0-4.2V)", + "appSettings_mapDisplay": "地图显示", + "appSettings_showRepeaters": "显示循环器", + "appSettings_showRepeatersSubtitle": "在地图上显示重复节点", + "appSettings_showChatNodes": "显示聊天节点", + "appSettings_showChatNodesSubtitle": "在地图上显示聊天节点", + "appSettings_showOtherNodes": "显示其他节点", + "appSettings_showOtherNodesSubtitle": "显示其他节点类型在地图上", + "appSettings_timeFilter": "时间筛选", + "appSettings_timeFilterShowAll": "显示所有节点", + "appSettings_timeFilterShowLast": "显示来自过去 {hours} 小时的节点", + "@appSettings_timeFilterShowLast": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "appSettings_mapTimeFilter": "地图时间筛选", + "appSettings_showNodesDiscoveredWithin": "显示发现的节点在:", + "appSettings_allTime": "所有时间", + "appSettings_lastHour": "最后小时", + "appSettings_last6Hours": "最后6小时", + "appSettings_last24Hours": "最后24小时", + "appSettings_lastWeek": "上周", + "appSettings_offlineMapCache": "离线地图缓存", + "appSettings_noAreaSelected": "未选择任何区域", + "appSettings_areaSelectedZoom": "选中的区域(缩放至 {minZoom} - {maxZoom})", + "@appSettings_areaSelectedZoom": { + "placeholders": { + "minZoom": { + "type": "int" + }, + "maxZoom": { + "type": "int" + } + } + }, + "appSettings_debugCard": "调试", + "appSettings_appDebugLogging": "应用调试日志", + "appSettings_appDebugLoggingSubtitle": "记录应用调试消息以供故障排除", + "appSettings_appDebugLoggingEnabled": "应用调试日志已启用", + "appSettings_appDebugLoggingDisabled": "应用调试日志已禁用", + "contacts_title": "联系人", + "contacts_noContacts": "还没有联系人", + "contacts_contactsWillAppear": "设备会广播时,联系人会显示", + "contacts_searchContacts": "搜索联系人...", + "contacts_noUnreadContacts": "未读联系人", + "contacts_noContactsFound": "未找到任何联系人或群组", + "contacts_deleteContact": "删除联系人", + "contacts_removeConfirm": "从联系人中删除 {contactName} 吗?", + "@contacts_removeConfirm": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "contacts_manageRepeater": "管理重复项", + "contacts_roomLogin": "房间登录", + "contacts_openChat": "打开聊天", + "contacts_editGroup": "编辑组", + "contacts_deleteGroup": "删除分组", + "contacts_deleteGroupConfirm": "删除\"{groupName}\"?", + "@contacts_deleteGroupConfirm": { + "placeholders": { + "groupName": { + "type": "String" + } + } + }, + "contacts_newGroup": "新组", + "contacts_groupName": "组名", + "contacts_groupNameRequired": "组名不能为空", + "contacts_groupAlreadyExists": "组“{name}”已存在", + "@contacts_groupAlreadyExists": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "contacts_filterContacts": "筛选联系人...", + "contacts_noContactsMatchFilter": "未找到匹配您的筛选条件的结果", + "contacts_noMembers": "没有会员", + "contacts_lastSeenNow": "最后一次登录时间现在", + "contacts_lastSeenMinsAgo": "最后一次出现 {minutes} 分前", + "@contacts_lastSeenMinsAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "contacts_lastSeenHourAgo": "最后一次出现前1小时", + "contacts_lastSeenHoursAgo": "最后一次出现 {hours} 小时前", + "@contacts_lastSeenHoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "contacts_lastSeenDayAgo": "最后一次登录前一天", + "contacts_lastSeenDaysAgo": "最后一次出现 {days} 天前", + "@contacts_lastSeenDaysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "channels_title": "频道", + "channels_noChannelsConfigured": "未配置任何频道", + "channels_addPublicChannel": "添加公开频道", + "channels_searchChannels": "搜索频道...", + "channels_noChannelsFound": "未找到任何频道", + "channels_channelIndex": "频道 {index}", + "@channels_channelIndex": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_hashtagChannel": "话题频道", + "channels_public": "公开", + "channels_private": "私有", + "channels_publicChannel": "公开频道", + "channels_privateChannel": "私聊频道", + "channels_editChannel": "编辑频道", + "channels_deleteChannel": "删除频道", + "channels_deleteChannelConfirm": "删除\"{name}\"?此操作无法撤销。", + "@channels_deleteChannelConfirm": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_channelDeleted": "频道“{name}”已删除", + "@channels_channelDeleted": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_addChannel": "添加频道", + "channels_channelIndexLabel": "频道索引", + "channels_channelName": "频道名称", + "channels_usePublicChannel": "使用公共频道", + "channels_standardPublicPsk": "标准公钥共享密钥", + "channels_pskHex": "PSK (十六进制)", + "channels_generateRandomPsk": "生成随机PSK", + "channels_enterChannelName": "请输入频道名称", + "channels_pskMustBe32Hex": "PSK 必须是 32 个十六进制字符", + "channels_channelAdded": "频道“{name}”已添加", + "@channels_channelAdded": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_editChannelTitle": "编辑频道 {index}", + "@channels_editChannelTitle": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channels_smazCompression": "SMAZ 压缩", + "channels_channelUpdated": "频道“{name}”已更新", + "@channels_channelUpdated": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "channels_publicChannelAdded": "公共频道已添加", + "channels_sortBy": "按类型排序", + "channels_sortManual": "手动", + "channels_sortAZ": "A-Z", + "channels_sortLatestMessages": "最新消息", + "channels_sortUnread": "未读", + "chat_noMessages": "目前还没有消息", + "chat_sendMessageToStart": "发送消息开始", + "chat_originalMessageNotFound": "找不到原始消息", + "chat_replyingTo": "回复 {name}", + "@chat_replyingTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_replyTo": "回复 {name}", + "@chat_replyTo": { + "placeholders": { + "name": { + "type": "String" + } + } + }, + "chat_location": "位置", + "chat_sendMessageTo": "向{contactName}发送消息", + "@chat_sendMessageTo": { + "placeholders": { + "contactName": { + "type": "String" + } + } + }, + "chat_typeMessage": "输入消息...", + "chat_messageTooLong": "消息太长了(最大 {maxBytes} 字节)。", + "@chat_messageTooLong": { + "placeholders": { + "maxBytes": { + "type": "int" + } + } + }, + "chat_messageCopied": "消息已复制", + "chat_messageDeleted": "消息已删除", + "chat_retryingMessage": "重试", + "chat_retryCount": "重试 {current}/{max}", + "@chat_retryCount": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "chat_sendGif": "发送GIF", + "chat_reply": "回复", + "chat_addReaction": "添加反应", + "chat_me": "我", + "emojiCategorySmileys": "表情符号", + "emojiCategoryGestures": "手势", + "emojiCategoryHearts": "心", + "emojiCategoryObjects": "对象", + "gifPicker_title": "选择一个 GIF", + "gifPicker_searchHint": "搜索GIF...", + "gifPicker_poweredBy": "由 GIPHY 提供支持", + "gifPicker_noGifsFound": "未找到 GIF 动画", + "gifPicker_failedLoad": "GIF 加载失败", + "gifPicker_failedSearch": "搜索GIF失败", + "gifPicker_noInternet": "无网络连接", + "debugLog_appTitle": "应用调试日志", + "debugLog_bleTitle": "蓝牙调试日志", + "debugLog_copyLog": "复制日志", + "debugLog_clearLog": "清除日志", + "debugLog_copied": "调试日志已复制", + "debugLog_bleCopied": "蓝牙日志复制", + "debugLog_noEntries": "尚未生成调试日志", + "debugLog_enableInSettings": "启用应用调试日志记录设置", + "debugLog_frames": "帧", + "debugLog_rawLogRx": "原始日志-RX", + "debugLog_noBleActivity": "目前还没有蓝牙活动。", + "debugFrame_length": "帧长度:{count} 字节", + "@debugFrame_length": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "debugFrame_command": "命令:0x{value}", + "@debugFrame_command": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textMessageHeader": "短信框", + "debugFrame_destinationPubKey": "- 目的地公钥:{pubKey}", + "@debugFrame_destinationPubKey": { + "placeholders": { + "pubKey": { + "type": "String" + } + } + }, + "debugFrame_timestamp": "- 时间戳:{timestamp}", + "@debugFrame_timestamp": { + "placeholders": { + "timestamp": { + "type": "int" + } + } + }, + "debugFrame_flags": "- 标志:0x{value}", + "@debugFrame_flags": { + "placeholders": { + "value": { + "type": "String" + } + } + }, + "debugFrame_textType": "- 文本类型:{type} ({label})", + "@debugFrame_textType": { + "placeholders": { + "type": { + "type": "int" + }, + "label": { + "type": "String" + } + } + }, + "debugFrame_textTypeCli": "CLI", + "debugFrame_textTypePlain": "简洁", + "debugFrame_text": "- 文本:\"{text}\"", + "@debugFrame_text": { + "placeholders": { + "text": { + "type": "String" + } + } + }, + "debugFrame_hexDump": "十六进制数据", + "chat_pathManagement": "路径管理", + "chat_routingMode": "路由模式", + "chat_autoUseSavedPath": "自动(使用已保存路径)", + "chat_forceFloodMode": "强制洪水模式", + "chat_recentAckPaths": "最近的 ACK 路径 (点击以使用):", + "chat_pathHistoryFull": "路径历史已满。删除条目以添加新条目。", + "chat_hopSingular": "跳转", + "chat_hopPlural": "跳跃", + "chat_hopsCount": "{count} {count, plural, =1{跳跃} other{跳跃}}", + "@chat_hopsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_successes": "成功", + "chat_removePath": "删除路径", + "chat_noPathHistoryYet": "还没有历史记录。\n发送消息以发现路径。", + "chat_pathActions": "路径操作:", + "chat_setCustomPath": "设置自定义路径", + "chat_setCustomPathSubtitle": "手动指定路由路径", + "chat_clearPath": "清除路径", + "chat_clearPathSubtitle": "强制下次发送时重新发现", + "chat_pathCleared": "路径已清除。下一条消息将重新发现路线。", + "chat_floodModeSubtitle": "使用应用栏中的路由切换开关", + "chat_floodModeEnabled": "防洪模式已启用。通过应用程序栏中的路由图标进行反转。", + "chat_fullPath": "完整路径", + "chat_pathDetailsNotAvailable": "路径详情尚未获取。请尝试发送消息以刷新。", + "chat_pathSetHops": "路径设置:{hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "@chat_pathSetHops": { + "placeholders": { + "hopCount": { + "type": "int" + }, + "status": { + "type": "String" + } + } + }, + "chat_pathSavedLocally": "已本地保存。连接以同步。", + "chat_pathDeviceConfirmed": "设备已确认。", + "chat_pathDeviceNotConfirmed": "设备尚未确认。", + "chat_type": "输入", + "chat_path": "路径", + "chat_publicKey": "公钥", + "chat_compressOutgoingMessages": "压缩发送的消息", + "chat_floodForced": "强制溢出", + "chat_directForced": "强制直接", + "chat_hopsForced": "{count} 次跳跃 (强制)", + "@chat_hopsForced": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "chat_floodAuto": "自动防洪", + "chat_direct": "直接", + "chat_poiShared": "共享位置信息", + "chat_unread": "未读:{count}", + "@chat_unread": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_title": "节点地图", + "map_noNodesWithLocation": "没有具有位置数据的节点", + "map_nodesNeedGps": "节点需要共享它们的 GPS 坐标\n才能在地图上显示", + "map_nodesCount": "节点:{count}", + "@map_nodesCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_pinsCount": "针:{count}", + "@map_pinsCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "map_chat": "聊天", + "map_repeater": "重复器", + "map_room": "房间", + "map_sensor": "传感器", + "map_pinDm": "私信 (DM)", + "map_pinPrivate": "私密模式", + "map_pinPublic": "公开(公版)", + "map_lastSeen": "最后一次登录", + "map_disconnectConfirm": "您确定要断开与此设备的连接吗?", + "map_from": "从", + "map_source": "来源", + "map_flags": "旗帜", + "map_shareMarkerHere": "分享标记在此", + "map_pinLabel": "固定标签", + "map_label": "标签", + "map_pointOfInterest": "兴趣点", + "map_sendToContact": "发送给联系人", + "map_sendToChannel": "发送到频道", + "map_noChannelsAvailable": "没有可用的频道", + "map_publicLocationShare": "公共位置共享", + "map_publicLocationShareConfirm": "您即将分享一个位置在 {channelLabel}。此频道公开,任何拥有 PSK 的人都可以看到它。", + "@map_publicLocationShareConfirm": { + "placeholders": { + "channelLabel": { + "type": "String" + } + } + }, + "map_connectToShareMarkers": "连接设备以共享标记", + "map_filterNodes": "筛选节点", + "map_nodeTypes": "节点类型", + "map_chatNodes": "聊天节点", + "map_repeaters": "重复器", + "map_otherNodes": "其他节点", + "map_keyPrefix": "键前缀", + "map_filterByKeyPrefix": "按关键词前缀筛选", + "map_publicKeyPrefix": "公钥前缀", + "map_markers": "标记", + "map_showSharedMarkers": "显示共享标记", + "map_lastSeenTime": "最后一次查看时间", + "map_sharedPin": "共享 PIN", + "map_joinRoom": "加入房间", + "map_manageRepeater": "管理重复项", + "mapCache_title": "离线地图缓存", + "mapCache_selectAreaFirst": "选择一个区域进行缓存", + "mapCache_noTilesToDownload": "该区域没有可下载的瓦片。", + "mapCache_downloadTilesTitle": "下载瓦片", + "mapCache_downloadTilesPrompt": "下载 {count} 个瓦片用于离线使用?", + "@mapCache_downloadTilesPrompt": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadAction": "下载", + "mapCache_cachedTiles": "已缓存 {count} 个瓦片", + "@mapCache_cachedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_cachedTilesWithFailed": "已缓存 {downloaded} 个瓦片 ({failed} 失败)", + "@mapCache_cachedTilesWithFailed": { + "placeholders": { + "downloaded": { + "type": "int" + }, + "failed": { + "type": "int" + } + } + }, + "mapCache_clearOfflineCacheTitle": "清除离线缓存", + "mapCache_clearOfflineCachePrompt": "删除所有缓存地图瓦片?", + "mapCache_offlineCacheCleared": "离线缓存已清除", + "mapCache_noAreaSelected": "未选择任何区域", + "mapCache_cacheArea": "缓存区域", + "mapCache_useCurrentView": "使用当前视图", + "mapCache_zoomRange": "缩放范围", + "mapCache_estimatedTiles": "预计瓦片数量:{count}", + "@mapCache_estimatedTiles": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_downloadedTiles": "已下载 {completed} / {total}", + "@mapCache_downloadedTiles": { + "placeholders": { + "completed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "mapCache_downloadTilesButton": "下载瓦片", + "mapCache_clearCacheButton": "清除缓存", + "mapCache_failedDownloads": "下载失败:{count}", + "@mapCache_failedDownloads": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "mapCache_boundsLabel": "北 {north}, 南 {south}, 东 {east}, 西 {west}", + "@mapCache_boundsLabel": { + "placeholders": { + "north": { + "type": "String" + }, + "south": { + "type": "String" + }, + "east": { + "type": "String" + }, + "west": { + "type": "String" + } + } + }, + "time_justNow": "刚才", + "time_minutesAgo": "{minutes}分钟前", + "@time_minutesAgo": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "time_hoursAgo": "{hours}小时前", + "@time_hoursAgo": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "time_daysAgo": "{days} 天前", + "@time_daysAgo": { + "placeholders": { + "days": { + "type": "int" + } + } + }, + "time_hour": "小时", + "time_hours": "小时", + "time_day": "今天", + "time_days": "天", + "time_week": "本周", + "time_weeks": "几周", + "time_month": "月份", + "time_months": "月份", + "time_minutes": "分钟", + "time_allTime": "所有时间", + "dialog_disconnect": "断开", + "dialog_disconnectConfirm": "您确定要断开与此设备的连接吗?", + "login_repeaterLogin": "重复登录", + "login_roomLogin": "房间登录", + "login_password": "密码", + "login_enterPassword": "请输入密码", + "login_savePassword": "保存密码", + "login_savePasswordSubtitle": "密码将安全地存储在这个设备上", + "login_repeaterDescription": "输入重复密码以访问设置和状态。", + "login_roomDescription": "输入房间密码以访问设置和状态。", + "login_routing": "路由", + "login_routingMode": "路由模式", + "login_autoUseSavedPath": "自动(使用已保存路径)", + "login_forceFloodMode": "强制洪水模式", + "login_managePaths": "管理路径", + "login_login": "登录", + "login_attempt": "尝试 {current}/{max}", + "@login_attempt": { + "placeholders": { + "current": { + "type": "int" + }, + "max": { + "type": "int" + } + } + }, + "login_failed": "登录失败:{error}", + "@login_failed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "common_reload": "重新加载", + "common_clear": "清除", + "path_currentPath": "当前路径:{path}", + "@path_currentPath": { + "placeholders": { + "path": { + "type": "String" + } + } + }, + "path_usingHopsPath": "使用 {count} {count, plural, =1{hop} other{hops}} 路径", + "@path_usingHopsPath": { + "placeholders": { + "count": { + "type": "int" + } + } + }, + "path_enterCustomPath": "输入自定义路径", + "path_currentPathLabel": "当前路径", + "path_hexPrefixInstructions": "输入2个字符的十六进制前缀,每个前缀之间用逗号分隔。", + "path_hexPrefixExample": "A1,F2,3C (每个节点使用其公钥的第一字节)", + "path_labelHexPrefixes": "十六进制前缀", + "path_helperMaxHops": "最大 64 步跳。每个前缀是 2 个十六进制字符(1 字节)", + "path_selectFromContacts": "或从联系人中选择:", + "path_noRepeatersFound": "未找到任何重复器或房间服务器。", + "path_customPathsRequire": "自定义路径需要中间跳转,这些跳转可以传递消息。", + "path_invalidHexPrefixes": "无效的十六进制前缀:{prefixes}", + "@path_invalidHexPrefixes": { + "placeholders": { + "prefixes": { + "type": "String" + } + } + }, + "path_tooLong": "路径太长。允许的最大跳跃次数为 64 次。", + "path_setPath": "设置路径", + "repeater_management": "重复器管理", + "repeater_managementTools": "管理工具", + "repeater_status": "状态", + "repeater_statusSubtitle": "查看重复器状态、统计信息和邻居", + "repeater_telemetry": "遥测", + "repeater_telemetrySubtitle": "查看传感器和系统状态的Telemetry数据", + "repeater_cli": "CLI", + "repeater_cliSubtitle": "发送命令到重复器", + "repeater_settings": "设置", + "repeater_settingsSubtitle": "配置重复器参数", + "repeater_statusTitle": "重复器状态", + "repeater_routingMode": "路由模式", + "repeater_autoUseSavedPath": "自动(使用已保存路径)", + "repeater_forceFloodMode": "强制洪水模式", + "repeater_pathManagement": "路径管理", + "repeater_refresh": "刷新", + "repeater_statusRequestTimeout": "状态请求超时。", + "repeater_errorLoadingStatus": "错误加载状态:{error}", + "@repeater_errorLoadingStatus": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_systemInformation": "系统信息", + "repeater_battery": "电池", + "repeater_clockAtLogin": "时间 (登录时)", + "repeater_uptime": "可用时间", + "repeater_queueLength": "排队长度", + "repeater_debugFlags": "调试标志", + "repeater_radioStatistics": "无线电统计", + "repeater_lastRssi": "上次RSSI", + "repeater_lastSnr": "最后 SNR", + "repeater_noiseFloor": "噪声地板", + "repeater_txAirtime": "TX Airtime", + "repeater_rxAirtime": "RX Airtime", + "repeater_packetStatistics": "数据包统计", + "repeater_sent": "已发送", + "repeater_received": "已收到", + "repeater_duplicates": "重复", + "repeater_daysHoursMinsSecs": "{days}天 {hours}小时 {minutes}分 {seconds}秒", + "@repeater_daysHoursMinsSecs": { + "placeholders": { + "days": { + "type": "int" + }, + "hours": { + "type": "int" + }, + "minutes": { + "type": "int" + }, + "seconds": { + "type": "int" + } + } + }, + "repeater_packetTxTotal": "总计:{total}, 洪流:{flood}, 直连:{direct}", + "@repeater_packetTxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_packetRxTotal": "总计:{total}, 洪流:{flood}, 直连:{direct}", + "@repeater_packetRxTotal": { + "placeholders": { + "total": { + "type": "int" + }, + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesFloodDirect": "洪水:{flood}, 直通:{direct}", + "@repeater_duplicatesFloodDirect": { + "placeholders": { + "flood": { + "type": "String" + }, + "direct": { + "type": "String" + } + } + }, + "repeater_duplicatesTotal": "总计:{total}", + "@repeater_duplicatesTotal": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "repeater_settingsTitle": "重复设置", + "repeater_basicSettings": "基本设置", + "repeater_repeaterName": "重复器名称", + "repeater_repeaterNameHelper": "显示此重复器的名称", + "repeater_adminPassword": "管理员密码", + "repeater_adminPasswordHelper": "完整访问密码", + "repeater_guestPassword": "访客密码", + "repeater_guestPasswordHelper": "只读访问密码", + "repeater_radioSettings": "射频设置", + "repeater_frequencyMhz": "频率 (MHz)", + "repeater_frequencyHelper": "300-2500 MHz", + "repeater_txPower": "TX Power", + "repeater_txPowerHelper": "1-30 dBm", + "repeater_bandwidth": "带宽", + "repeater_spreadingFactor": "扩散因子", + "repeater_codingRate": "编码速率", + "repeater_locationSettings": "位置设置", + "repeater_latitude": "纬度", + "repeater_latitudeHelper": "十进度的数字(例如:37.7749)", + "repeater_longitude": "经度", + "repeater_longitudeHelper": "十进度的数字(例如:-122.4194)", + "repeater_features": "功能", + "repeater_packetForwarding": "数据包转发", + "repeater_packetForwardingSubtitle": "启用重复器以转发数据包", + "repeater_guestAccess": "访客访问", + "repeater_guestAccessSubtitle": "允许访客仅读访问", + "repeater_privacyMode": "隐私模式", + "repeater_privacyModeSubtitle": "隐藏在广告中的姓名/位置", + "repeater_advertisementSettings": "广告设置", + "repeater_localAdvertInterval": "本地广告间隔", + "repeater_localAdvertIntervalMinutes": "{minutes} 分钟", + "@repeater_localAdvertIntervalMinutes": { + "placeholders": { + "minutes": { + "type": "int" + } + } + }, + "repeater_floodAdvertInterval": "洪水广告间隔", + "repeater_floodAdvertIntervalHours": "{hours} 小时", + "@repeater_floodAdvertIntervalHours": { + "placeholders": { + "hours": { + "type": "int" + } + } + }, + "repeater_encryptedAdvertInterval": "加密广告间隔", + "repeater_dangerZone": "危险区域", + "repeater_rebootRepeater": "重启重复器", + "repeater_rebootRepeaterSubtitle": "重启重复器设备", + "repeater_rebootRepeaterConfirm": "您确定要重启这个中继器吗?", + "repeater_regenerateIdentityKey": "重新生成身份密钥", + "repeater_regenerateIdentityKeySubtitle": "生成新的公钥/私钥对", + "repeater_regenerateIdentityKeyConfirm": "这将生成一个重复器的新身份。继续吗?", + "repeater_eraseFileSystem": "删除文件系统", + "repeater_eraseFileSystemSubtitle": "格式化重复文件系统", + "repeater_eraseFileSystemConfirm": "警告:这将擦除重复器上的所有数据。 这无法撤销!", + "repeater_eraseSerialOnly": "通过串行控制台才能删除。", + "repeater_commandSent": "命令已发送:{command}", + "@repeater_commandSent": { + "placeholders": { + "command": { + "type": "String" + } + } + }, + "repeater_errorSendingCommand": "发送命令时出错:{error}", + "@repeater_errorSendingCommand": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_confirm": "确认", + "repeater_settingsSaved": "设置已保存成功", + "repeater_errorSavingSettings": "保存设置出错:{error}", + "@repeater_errorSavingSettings": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_refreshBasicSettings": "刷新基本设置", + "repeater_refreshRadioSettings": "刷新无线电设置", + "repeater_refreshTxPower": "刷新 TX 电量", + "repeater_refreshLocationSettings": "刷新位置设置", + "repeater_refreshPacketForwarding": "刷新包转发", + "repeater_refreshGuestAccess": "刷新访客访问", + "repeater_refreshPrivacyMode": "刷新隐私模式", + "repeater_refreshAdvertisementSettings": "刷新广告设置", + "repeater_refreshed": "{label} 已刷新", + "@repeater_refreshed": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_errorRefreshing": "刷新 {label} 时出错", + "@repeater_errorRefreshing": { + "placeholders": { + "label": { + "type": "String" + } + } + }, + "repeater_cliTitle": "重复器命令行工具", + "repeater_debugNextCommand": "调试下一步命令", + "repeater_commandHelp": "帮助", + "repeater_clearHistory": "清除历史", + "repeater_noCommandsSent": "尚未发送任何命令", + "repeater_typeCommandOrUseQuick": "输入命令或使用快捷命令", + "repeater_enterCommandHint": "输入命令...", + "repeater_previousCommand": "上一个命令", + "repeater_nextCommand": "下一步命令", + "repeater_enterCommandFirst": "请输入一个命令", + "repeater_cliCommandFrameTitle": "CLI 命令窗口", + "repeater_cliCommandError": "错误:{error}", + "@repeater_cliCommandError": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "repeater_cliQuickGetName": "获取姓名", + "repeater_cliQuickGetRadio": "获取收音机", + "repeater_cliQuickGetTx": "获取 TX", + "repeater_cliQuickNeighbors": "邻居", + "repeater_cliQuickVersion": "版本", + "repeater_cliQuickAdvertise": "发布", + "repeater_cliQuickClock": "时钟", + "repeater_cliHelpAdvert": "发送广告包", + "repeater_cliHelpReboot": "重启设备。(请注意,可能会出现“超时”现象,这是正常现象)", + "repeater_cliHelpClock": "显示每个设备的当前时间。", + "repeater_cliHelpPassword": "设置设备的新管理员密码。", + "repeater_cliHelpVersion": "显示设备版本和固件构建日期。", + "repeater_cliHelpClearStats": "重置各种统计数值为零。", + "repeater_cliHelpSetAf": "设置空闲时间因子。", + "repeater_cliHelpSetTx": "设置 LoRa 传输功率 (重置生效)", + "repeater_cliHelpSetRepeat": "启用或禁用此节点的重复器角色。", + "repeater_cliHelpSetAllowReadOnly": "(房间服务器) 如果“开”了,则空密码登录将被允许,但不能向房间发布内容。(仅限读取)", + "repeater_cliHelpSetFloodMax": "设置最大换路包数量(如果 >= 最大,则不转发包)。", + "repeater_cliHelpSetIntThresh": "设置干扰阈值(以 dB 为单位)。默认值为 14。将设置为 0 以禁用通道干扰检测。", + "repeater_cliHelpSetAgcResetInterval": "设置间隔以重置自动增益控制器。将设置为 0 以禁用。", + "repeater_cliHelpSetMultiAcks": "启用或禁用“双 ACKs”功能。", + "repeater_cliHelpSetAdvertInterval": "设置定时器间隔时间为分钟,以发送本地(零跳)广告包。将设置为0以禁用。", + "repeater_cliHelpSetFloodAdvertInterval": "设置定时器间隔时间为小时,以发送洪水广告包。将设置为 0 以禁用。", + "repeater_cliHelpSetGuestPassword": "设置/更新客人密码。(对于重复器,客人在登录时可以发送“获取统计”请求)", + "repeater_cliHelpSetName": "设置广告名称。", + "repeater_cliHelpSetLat": "设置广告地图纬度(十进制度)", + "repeater_cliHelpSetLon": "设置广告地图经度 (十进位)", + "repeater_cliHelpSetRadio": "设置全新的无线电参数,并保存到偏好设置。需要执行“重启”命令才能应用。", + "repeater_cliHelpSetRxDelay": "设置(实验性)的基础(必须大于 1 才能生效)是用于对接收到的数据包应用轻微延迟,基于信号强度/得分。将设置为 0 以禁用。", + "repeater_cliHelpSetTxDelay": "设置一个与时间-在空气中(time-on-air)的系数,用于洪水模式的数据包,并结合随机插槽系统,以延迟其转发。(以降低碰撞的可能性)", + "repeater_cliHelpSetDirectTxDelay": "与txdelay相同,但用于为直接模式包的转发应用随机延迟。", + "repeater_cliHelpSetBridgeEnabled": "启用/禁用桥梁", + "repeater_cliHelpSetBridgeDelay": "设置在重新发送数据包之前延迟时间。", + "repeater_cliHelpSetBridgeSource": "选择桥梁是否会重传接收到的数据包或发送的数据包。", + "repeater_cliHelpSetBridgeBaud": "设置rs232桥接的串口链路波特率。", + "repeater_cliHelpSetBridgeSecret": "设置 espnow 桥的秘密。", + "repeater_cliHelpSetAdcMultiplier": "设置自定义因子以调整报告的电池电压(仅限部分板卡支持)。", + "repeater_cliHelpTempRadio": "设置临时无线电参数,持续指定的分钟数,之后恢复为原始无线电参数。(不保存到偏好设置)。", + "repeater_cliHelpSetPerm": "修改ACL。如果“权限”为零,则删除匹配的条目(通过pubkey前缀)。如果pubkey-hex的完整长度且当前不在ACL中,则添加新条目。通过匹配pubkey前缀更新条目。权限位因固件角色而异,但低2位为:0(Guest)、1(只读)、2(读写)、3(Admin)", + "repeater_cliHelpGetBridgeType": "获取桥接类型:无,RS232,ESPNow", + "repeater_cliHelpLogStart": "开始将数据包记录到文件系统。", + "repeater_cliHelpLogStop": "停止将数据包记录到文件系统。", + "repeater_cliHelpLogErase": "删除文件系统中的包日志。", + "repeater_cliHelpNeighbors": "显示通过零跳广告收听的其他重复节点列表。 每行是 id-prefix-hex:时间戳:snr-times-4", + "repeater_cliHelpNeighborRemove": "移除邻居列表中第一个匹配的条目(通过十六进制 pubkey 前缀)。", + "repeater_cliHelpRegion": "(仅显示区域) 列出所有已定义的区域和当前的防洪权限。", + "repeater_cliHelpRegionLoad": "注意:这是一个特殊的多命令调用。 随后的每个命令都是一个区域名称(用空格缩进以指示父级层次结构,至少需要一个空格)。 以发送一个空行/命令结束。", + "repeater_cliHelpRegionGet": "搜索具有给定名称前缀的区域(或“”用于全局范围)。回复为“-> region-name (parent-name) ‘F’”", + "repeater_cliHelpRegionPut": "添加或更新区域定义,使用指定名称。", + "repeater_cliHelpRegionRemove": "删除指定名称的区域定义。(必须没有子区域)", + "repeater_cliHelpRegionAllowf": "设置指定区域的“洪水”权限。(“”代表全局/遗留范围)", + "repeater_cliHelpRegionDenyf": "移除指定区域的‘F’lood权限。 (注意:目前阶段不建议在此范围内使用,尤其是全局/旧版范围!!)", + "repeater_cliHelpRegionHome": "回复当前“主页”区域。 (注意尚未应用,保留用于未来)", + "repeater_cliHelpRegionHomeSet": "设置‘主页’区域。", + "repeater_cliHelpRegionSave": "保存区域列表/地图到存储。", + "repeater_cliHelpGps": "显示GPS状态。当GPS关闭时,回复仅为“关闭”,如果已开启,则回复为“开启”、“状态”、“定位”和卫星数量。", + "repeater_cliHelpGpsOnOff": "切换 GPS 开启状态。", + "repeater_cliHelpGpsSync": "同步节点时间与 GPS 钟。", + "repeater_cliHelpGpsSetLoc": "设置节点位置至 GPS 坐标并保存偏好设置。", + "repeater_cliHelpGpsAdvert": "提供节点广告配置位置:\n- none:不包含位置在广告中\n- share:分享 GPS 位置(来自 SensorManager)\n- prefs:在偏好设置中投放位置", + "repeater_cliHelpGpsAdvertSet": "设置广告位置配置。", + "repeater_commandsListTitle": "命令列表", + "repeater_commandsListNote": "注意:对于各种“设置...”命令,也存在“获取...”命令。", + "repeater_general": "通用", + "repeater_settingsCategory": "设置", + "repeater_bridge": "桥", + "repeater_logging": "记录", + "repeater_neighborsRepeaterOnly": "邻居(仅限重复器)", + "repeater_regionManagementRepeaterOnly": "区域管理(仅限重复器)", + "repeater_regionNote": "区域命令已推出,用于管理区域定义和权限。", + "repeater_gpsManagement": "GPS管理", + "repeater_gpsNote": "GPS 命令已引入用于管理与位置相关的主题。", + "telemetry_receivedData": "接收遥测数据", + "telemetry_requestTimeout": "遥测请求超时。", + "telemetry_errorLoading": "错误加载遥测数据:{error}", + "@telemetry_errorLoading": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "telemetry_noData": "没有可用的 telemetry 数据。", + "telemetry_channelTitle": "频道 {channel}", + "@telemetry_channelTitle": { + "placeholders": { + "channel": { + "type": "int" + } + } + }, + "telemetry_batteryLabel": "电池", + "telemetry_voltageLabel": "电压", + "telemetry_mcuTemperatureLabel": "MCU 温度", + "telemetry_temperatureLabel": "温度", + "telemetry_currentLabel": "当前", + "telemetry_batteryValue": "{percent}% / {volts}V", + "@telemetry_batteryValue": { + "placeholders": { + "percent": { + "type": "int" + }, + "volts": { + "type": "String" + } + } + }, + "telemetry_voltageValue": "{volts}V", + "@telemetry_voltageValue": { + "placeholders": { + "volts": { + "type": "String" + } + } + }, + "telemetry_currentValue": "{amps}A", + "@telemetry_currentValue": { + "placeholders": { + "amps": { + "type": "String" + } + } + }, + "telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F", + "@telemetry_temperatureValue": { + "placeholders": { + "celsius": { + "type": "String" + }, + "fahrenheit": { + "type": "String" + } + } + }, + "channelPath_title": "数据包路径", + "channelPath_viewMap": "查看地图", + "channelPath_otherObservedPaths": "其他观察到的路径", + "channelPath_repeaterHops": "重复跳跃", + "channelPath_noHopDetails": "此包的详细信息未提供。", + "channelPath_messageDetails": "消息详情", + "channelPath_senderLabel": "发件人", + "channelPath_timeLabel": "时间", + "channelPath_repeatsLabel": "重复", + "channelPath_pathLabel": "路径 {index}", + "channelPath_observedLabel": "已观察", + "channelPath_observedPathTitle": "观察路径 {index} • {hops}", + "@channelPath_observedPathTitle": { + "placeholders": { + "index": { + "type": "int" + }, + "hops": { + "type": "String" + } + } + }, + "channelPath_noLocationData": "没有位置数据", + "channelPath_timeWithDate": "{day}/{month} {time}", + "@channelPath_timeWithDate": { + "placeholders": { + "day": { + "type": "int" + }, + "month": { + "type": "int" + }, + "time": { + "type": "String" + } + } + }, + "channelPath_timeOnly": "{time}", + "@channelPath_timeOnly": { + "placeholders": { + "time": { + "type": "String" + } + } + }, + "channelPath_unknownPath": "未知", + "channelPath_floodPath": "洪水", + "channelPath_directPath": "直接", + "channelPath_observedZeroOf": "0 of {total} 跳跃", + "@channelPath_observedZeroOf": { + "placeholders": { + "total": { + "type": "int" + } + } + }, + "channelPath_observedSomeOf": "已观察到 {observed} 步中的 {total} 步", + "@channelPath_observedSomeOf": { + "placeholders": { + "observed": { + "type": "int" + }, + "total": { + "type": "int" + } + } + }, + "channelPath_mapTitle": "路径地图", + "channelPath_noRepeaterLocations": "此路径没有可用的重复器位置。", + "channelPath_primaryPath": "路径 {index} (主)", + "@channelPath_primaryPath": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "@channelPath_pathLabel": { + "placeholders": { + "index": { + "type": "int" + } + } + }, + "channelPath_pathLabelTitle": "路径", + "channelPath_observedPathHeader": "已观察路径", + "channelPath_selectedPathLabel": "{label} • {prefixes}", + "@channelPath_selectedPathLabel": { + "placeholders": { + "label": { + "type": "String" + }, + "prefixes": { + "type": "String" + } + } + }, + "channelPath_noHopDetailsAvailable": "此包的跳跃详情不可用。", + "channelPath_unknownRepeater": "未知重复器", + "listFilter_tooltip": "筛选和排序", + "listFilter_sortBy": "按类型排序", + "listFilter_latestMessages": "最新消息", + "listFilter_heardRecently": "最近听说", + "listFilter_az": "A-Z", + "listFilter_filters": "筛选", + "listFilter_all": "全部", + "listFilter_users": "用户", + "listFilter_repeaters": "重复器", + "listFilter_roomServers": "房间服务器", + "listFilter_unreadOnly": "未读消息", + "listFilter_newGroup": "新组" +} diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart new file mode 100644 index 0000000..f988960 --- /dev/null +++ b/lib/l10n/l10n.dart @@ -0,0 +1,6 @@ +import 'package:flutter/widgets.dart'; +import 'app_localizations.dart'; + +extension LocalizationExtension on BuildContext { + AppLocalizations get l10n => AppLocalizations.of(this); +} diff --git a/lib/main.dart b/lib/main.dart index 46e1641..4b59d8b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'l10n/app_localizations.dart'; import 'package:provider/provider.dart'; import 'connector/meshcore_connector.dart'; @@ -115,6 +117,14 @@ class MeshCoreApp extends StatelessWidget { return MaterialApp( title: 'MeshCore Open', debugShowCheckedModeBanner: false, + localizationsDelegates: const [ + AppLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: AppLocalizations.supportedLocales, + locale: _localeFromSetting(settingsService.settings.languageOverride), theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, @@ -144,4 +154,9 @@ class MeshCoreApp extends StatelessWidget { return ThemeMode.system; } } + + Locale? _localeFromSetting(String? languageCode) { + if (languageCode == null) return null; + return Locale(languageCode); + } } diff --git a/lib/models/app_settings.dart b/lib/models/app_settings.dart index a1769e0..50c31ba 100644 --- a/lib/models/app_settings.dart +++ b/lib/models/app_settings.dart @@ -18,6 +18,7 @@ class AppSettings { final bool notifyOnNewAdvert; final bool autoRouteRotationEnabled; final String themeMode; + final String? languageOverride; // null = system default final bool appDebugLogEnabled; final Map batteryChemistryByDeviceId; @@ -39,6 +40,7 @@ class AppSettings { this.notifyOnNewAdvert = true, this.autoRouteRotationEnabled = false, this.themeMode = 'system', + this.languageOverride, this.appDebugLogEnabled = false, Map? batteryChemistryByDeviceId, }) : batteryChemistryByDeviceId = batteryChemistryByDeviceId ?? {}; @@ -62,6 +64,7 @@ class AppSettings { 'notify_on_new_advert': notifyOnNewAdvert, 'auto_route_rotation_enabled': autoRouteRotationEnabled, 'theme_mode': themeMode, + 'language_override': languageOverride, 'app_debug_log_enabled': appDebugLogEnabled, 'battery_chemistry_by_device_id': batteryChemistryByDeviceId, }; @@ -89,6 +92,7 @@ class AppSettings { notifyOnNewAdvert: json['notify_on_new_advert'] as bool? ?? true, autoRouteRotationEnabled: json['auto_route_rotation_enabled'] as bool? ?? false, themeMode: json['theme_mode'] as String? ?? 'system', + languageOverride: json['language_override'] as String?, appDebugLogEnabled: json['app_debug_log_enabled'] as bool? ?? false, batteryChemistryByDeviceId: (json['battery_chemistry_by_device_id'] as Map?)?.map( (key, value) => MapEntry(key.toString(), value.toString()), @@ -115,6 +119,7 @@ class AppSettings { bool? notifyOnNewAdvert, bool? autoRouteRotationEnabled, String? themeMode, + Object? languageOverride = _unset, bool? appDebugLogEnabled, Map? batteryChemistryByDeviceId, }) { @@ -138,6 +143,8 @@ class AppSettings { notifyOnNewAdvert: notifyOnNewAdvert ?? this.notifyOnNewAdvert, autoRouteRotationEnabled: autoRouteRotationEnabled ?? this.autoRouteRotationEnabled, themeMode: themeMode ?? this.themeMode, + languageOverride: + languageOverride == _unset ? this.languageOverride : languageOverride as String?, appDebugLogEnabled: appDebugLogEnabled ?? this.appDebugLogEnabled, batteryChemistryByDeviceId: batteryChemistryByDeviceId ?? this.batteryChemistryByDeviceId, ); diff --git a/lib/screens/app_debug_log_screen.dart b/lib/screens/app_debug_log_screen.dart index feaec7b..bdeccdb 100644 --- a/lib/screens/app_debug_log_screen.dart +++ b/lib/screens/app_debug_log_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; +import '../l10n/l10n.dart'; import '../services/app_debug_log_service.dart'; class AppDebugLogScreen extends StatelessWidget { @@ -16,11 +17,11 @@ class AppDebugLogScreen extends StatelessWidget { return Scaffold( appBar: AppBar( - title: const Text('App Debug Log'), + title: Text(context.l10n.debugLog_appTitle), centerTitle: true, actions: [ IconButton( - tooltip: 'Copy log', + tooltip: context.l10n.debugLog_copyLog, icon: const Icon(Icons.copy), onPressed: hasEntries ? () async { @@ -31,13 +32,13 @@ class AppDebugLogScreen extends StatelessWidget { await Clipboard.setData(ClipboardData(text: text)); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Debug log copied')), + SnackBar(content: Text(context.l10n.debugLog_copied)), ); } : null, ), IconButton( - tooltip: 'Clear log', + tooltip: context.l10n.debugLog_clearLog, icon: const Icon(Icons.delete_outline), onPressed: hasEntries ? () { @@ -76,12 +77,12 @@ class AppDebugLogScreen extends StatelessWidget { Icon(Icons.bug_report_outlined, size: 64, color: Colors.grey[400]), const SizedBox(height: 16), Text( - 'No debug logs yet', + context.l10n.debugLog_noEntries, style: TextStyle(fontSize: 16, color: Colors.grey[600]), ), const SizedBox(height: 8), Text( - 'Enable app debug logging in settings', + context.l10n.debugLog_enableInSettings, style: TextStyle(fontSize: 12, color: Colors.grey[500]), ), ], diff --git a/lib/screens/app_settings_screen.dart b/lib/screens/app_settings_screen.dart index 2f5183b..377c39a 100644 --- a/lib/screens/app_settings_screen.dart +++ b/lib/screens/app_settings_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../connector/meshcore_connector.dart'; +import '../l10n/l10n.dart'; import '../services/app_settings_service.dart'; import '../services/notification_service.dart'; import 'map_cache_screen.dart'; @@ -13,7 +14,7 @@ class AppSettingsScreen extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('App Settings'), + title: Text(context.l10n.appSettings_title), centerTitle: true, ), body: SafeArea( @@ -47,20 +48,28 @@ class AppSettingsScreen extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( - 'Appearance', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + context.l10n.appSettings_appearance, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), ListTile( leading: const Icon(Icons.brightness_6_outlined), - title: const Text('Theme'), - subtitle: Text(_themeModeLabel(settingsService.settings.themeMode)), + title: Text(context.l10n.appSettings_theme), + subtitle: Text(_themeModeLabel(context, settingsService.settings.themeMode)), trailing: const Icon(Icons.chevron_right), onTap: () => _showThemeModeDialog(context, settingsService), ), + const Divider(height: 1), + ListTile( + leading: const Icon(Icons.language_outlined), + title: Text(context.l10n.appSettings_language), + subtitle: Text(_languageLabel(context, settingsService.settings.languageOverride)), + trailing: const Icon(Icons.chevron_right), + onTap: () => _showLanguageDialog(context, settingsService), + ), ], ), ); @@ -71,17 +80,17 @@ class AppSettingsScreen extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( - 'Notifications', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + context.l10n.appSettings_notifications, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), SwitchListTile( secondary: const Icon(Icons.notifications_outlined), - title: const Text('Enable Notifications'), - subtitle: const Text('Receive notifications for messages and adverts'), + title: Text(context.l10n.appSettings_enableNotifications), + subtitle: Text(context.l10n.appSettings_enableNotificationsSubtitle), value: settingsService.settings.notificationsEnabled, onChanged: (value) async { if (value) { @@ -90,9 +99,9 @@ class AppSettingsScreen extends StatelessWidget { if (!granted) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Notification permission denied'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(context.l10n.appSettings_notificationPermissionDenied), + duration: const Duration(seconds: 2), ), ); } @@ -105,8 +114,8 @@ class AppSettingsScreen extends StatelessWidget { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(value - ? 'Notifications enabled' - : 'Notifications disabled'), + ? context.l10n.appSettings_notificationsEnabled + : context.l10n.appSettings_notificationsDisabled), duration: const Duration(seconds: 2), ), ); @@ -120,13 +129,13 @@ class AppSettingsScreen extends StatelessWidget { color: settingsService.settings.notificationsEnabled ? null : Colors.grey, ), title: Text( - 'Message Notifications', + context.l10n.appSettings_messageNotifications, style: TextStyle( color: settingsService.settings.notificationsEnabled ? null : Colors.grey, ), ), subtitle: Text( - 'Show notification when receiving new messages', + context.l10n.appSettings_messageNotificationsSubtitle, style: TextStyle( color: settingsService.settings.notificationsEnabled ? null : Colors.grey, ), @@ -145,13 +154,13 @@ class AppSettingsScreen extends StatelessWidget { color: settingsService.settings.notificationsEnabled ? null : Colors.grey, ), title: Text( - 'Channel Message Notifications', + context.l10n.appSettings_channelMessageNotifications, style: TextStyle( color: settingsService.settings.notificationsEnabled ? null : Colors.grey, ), ), subtitle: Text( - 'Show notification when receiving channel messages', + context.l10n.appSettings_channelMessageNotificationsSubtitle, style: TextStyle( color: settingsService.settings.notificationsEnabled ? null : Colors.grey, ), @@ -170,13 +179,13 @@ class AppSettingsScreen extends StatelessWidget { color: settingsService.settings.notificationsEnabled ? null : Colors.grey, ), title: Text( - 'Advertisement Notifications', + context.l10n.appSettings_advertisementNotifications, style: TextStyle( color: settingsService.settings.notificationsEnabled ? null : Colors.grey, ), ), subtitle: Text( - 'Show notification when new nodes are discovered', + context.l10n.appSettings_advertisementNotificationsSubtitle, style: TextStyle( color: settingsService.settings.notificationsEnabled ? null : Colors.grey, ), @@ -198,25 +207,25 @@ class AppSettingsScreen extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( - 'Messaging', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + context.l10n.appSettings_messaging, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), SwitchListTile( secondary: const Icon(Icons.refresh_outlined), - title: const Text('Clear Path on Max Retry'), - subtitle: const Text('Reset contact path after 5 failed send attempts'), + title: Text(context.l10n.appSettings_clearPathOnMaxRetry), + subtitle: Text(context.l10n.appSettings_clearPathOnMaxRetrySubtitle), value: settingsService.settings.clearPathOnMaxRetry, onChanged: (value) { settingsService.setClearPathOnMaxRetry(value); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(value - ? 'Paths will be cleared after 5 failed retries' - : 'Paths will not be auto-cleared'), + ? context.l10n.appSettings_pathsWillBeCleared + : context.l10n.appSettings_pathsWillNotBeCleared), duration: const Duration(seconds: 2), ), ); @@ -225,16 +234,16 @@ class AppSettingsScreen extends StatelessWidget { const Divider(height: 1), SwitchListTile( secondary: const Icon(Icons.alt_route), - title: const Text('Auto Route Rotation'), - subtitle: const Text('Cycle between best paths and flood mode'), + title: Text(context.l10n.appSettings_autoRouteRotation), + subtitle: Text(context.l10n.appSettings_autoRouteRotationSubtitle), value: settingsService.settings.autoRouteRotationEnabled, onChanged: (value) { settingsService.setAutoRouteRotationEnabled(value); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(value - ? 'Auto route rotation enabled' - : 'Auto route rotation disabled'), + ? context.l10n.appSettings_autoRouteRotationEnabled + : context.l10n.appSettings_autoRouteRotationDisabled), duration: const Duration(seconds: 2), ), ); @@ -250,17 +259,17 @@ class AppSettingsScreen extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( - 'Map Display', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + context.l10n.appSettings_mapDisplay, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), SwitchListTile( secondary: const Icon(Icons.router_outlined), - title: const Text('Show Repeaters'), - subtitle: const Text('Display repeater nodes on the map'), + title: Text(context.l10n.appSettings_showRepeaters), + subtitle: Text(context.l10n.appSettings_showRepeatersSubtitle), value: settingsService.settings.mapShowRepeaters, onChanged: (value) { settingsService.setMapShowRepeaters(value); @@ -269,8 +278,8 @@ class AppSettingsScreen extends StatelessWidget { const Divider(height: 1), SwitchListTile( secondary: const Icon(Icons.chat_outlined), - title: const Text('Show Chat Nodes'), - subtitle: const Text('Display chat nodes on the map'), + title: Text(context.l10n.appSettings_showChatNodes), + subtitle: Text(context.l10n.appSettings_showChatNodesSubtitle), value: settingsService.settings.mapShowChatNodes, onChanged: (value) { settingsService.setMapShowChatNodes(value); @@ -279,8 +288,8 @@ class AppSettingsScreen extends StatelessWidget { const Divider(height: 1), SwitchListTile( secondary: const Icon(Icons.people_outline), - title: const Text('Show Other Nodes'), - subtitle: const Text('Display other node types on the map'), + title: Text(context.l10n.appSettings_showOtherNodes), + subtitle: Text(context.l10n.appSettings_showOtherNodesSubtitle), value: settingsService.settings.mapShowOtherNodes, onChanged: (value) { settingsService.setMapShowOtherNodes(value); @@ -289,11 +298,11 @@ class AppSettingsScreen extends StatelessWidget { const Divider(height: 1), ListTile( leading: const Icon(Icons.timer_outlined), - title: const Text('Time Filter'), + title: Text(context.l10n.appSettings_timeFilter), subtitle: Text( settingsService.settings.mapTimeFilterHours == 0 - ? 'Show all nodes' - : 'Show nodes from last ${settingsService.settings.mapTimeFilterHours.toInt()} hours', + ? context.l10n.appSettings_timeFilterShowAll + : context.l10n.appSettings_timeFilterShowLast(settingsService.settings.mapTimeFilterHours.toInt()), ), trailing: const Icon(Icons.chevron_right), onTap: () => _showTimeFilterDialog(context, settingsService), @@ -301,12 +310,14 @@ class AppSettingsScreen extends StatelessWidget { const Divider(height: 1), ListTile( leading: const Icon(Icons.download_outlined), - title: const Text('Offline Map Cache'), + title: Text(context.l10n.appSettings_offlineMapCache), subtitle: Text( settingsService.settings.mapCacheBounds == null - ? 'No area selected' - : 'Area selected (zoom ${settingsService.settings.mapCacheMinZoom}' - '-${settingsService.settings.mapCacheMaxZoom})', + ? context.l10n.appSettings_noAreaSelected + : context.l10n.appSettings_areaSelectedZoom( + settingsService.settings.mapCacheMinZoom, + settingsService.settings.mapCacheMaxZoom, + ), ), trailing: const Icon(Icons.chevron_right), onTap: () { @@ -335,20 +346,20 @@ class AppSettingsScreen extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( - 'Battery', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + context.l10n.appSettings_battery, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), ListTile( leading: const Icon(Icons.battery_full), - title: const Text('Battery Chemistry'), + title: Text(context.l10n.appSettings_batteryChemistry), subtitle: Text( isConnected - ? 'Set per device (${connector.deviceDisplayName})' - : 'Connect to a device to choose', + ? context.l10n.appSettings_batteryChemistryPerDevice(connector.deviceDisplayName) + : context.l10n.appSettings_batteryChemistryConnectFirst, ), trailing: DropdownButton( value: selection, @@ -359,18 +370,18 @@ class AppSettingsScreen extends StatelessWidget { } } : null, - items: const [ + items: [ DropdownMenuItem( value: 'nmc', - child: Text('18650 NMC (3.0-4.2V)'), + child: Text(context.l10n.appSettings_batteryNmc), ), DropdownMenuItem( value: 'lifepo4', - child: Text('LiFePO4 (2.6-3.65V)'), + child: Text(context.l10n.appSettings_batteryLifepo4), ), DropdownMenuItem( value: 'lipo', - child: Text('LiPo (3.0-4.2V)'), + child: Text(context.l10n.appSettings_batteryLipo), ), ], ), @@ -384,7 +395,7 @@ class AppSettingsScreen extends StatelessWidget { showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Theme'), + title: Text(context.l10n.appSettings_theme), content: RadioGroup( groupValue: settingsService.settings.themeMode, onChanged: (value) { @@ -397,15 +408,15 @@ class AppSettingsScreen extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ RadioListTile( - title: const Text('System default'), + title: Text(context.l10n.appSettings_themeSystem), value: 'system', ), RadioListTile( - title: const Text('Light'), + title: Text(context.l10n.appSettings_themeLight), value: 'light', ), RadioListTile( - title: const Text('Dark'), + title: Text(context.l10n.appSettings_themeDark), value: 'dark', ), ], @@ -414,29 +425,147 @@ class AppSettingsScreen extends StatelessWidget { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Close'), + child: Text(context.l10n.common_close), ), ], ), ); } - String _themeModeLabel(String value) { + String _themeModeLabel(BuildContext context, String value) { switch (value) { case 'light': - return 'Light'; + return context.l10n.appSettings_themeLight; case 'dark': - return 'Dark'; + return context.l10n.appSettings_themeDark; default: - return 'System default'; + return context.l10n.appSettings_themeSystem; } } + String _languageLabel(BuildContext context, String? languageCode) { + switch (languageCode) { + case 'en': + return context.l10n.appSettings_languageEn; + case 'fr': + return context.l10n.appSettings_languageFr; + case 'es': + return context.l10n.appSettings_languageEs; + case 'de': + return context.l10n.appSettings_languageDe; + case 'pl': + return context.l10n.appSettings_languagePl; + case 'sl': + return context.l10n.appSettings_languageSl; + case 'pt': + return context.l10n.appSettings_languagePt; + case 'it': + return context.l10n.appSettings_languageIt; + case 'zh': + return context.l10n.appSettings_languageZh; + case 'sv': + return context.l10n.appSettings_languageSv; + case 'nl': + return context.l10n.appSettings_languageNl; + case 'sk': + return context.l10n.appSettings_languageSk; + case 'bg': + return context.l10n.appSettings_languageBg; + default: + return context.l10n.appSettings_languageSystem; + } + } + + void _showLanguageDialog(BuildContext context, AppSettingsService settingsService) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(context.l10n.appSettings_language), + content: SingleChildScrollView( + child: RadioGroup( + groupValue: settingsService.settings.languageOverride, + onChanged: (value) { + settingsService.setLanguageOverride(value); + Navigator.pop(context); + }, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + RadioListTile( + title: Text(context.l10n.appSettings_languageSystem), + value: null, + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageEn), + value: 'en', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageFr), + value: 'fr', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageEs), + value: 'es', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageDe), + value: 'de', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languagePl), + value: 'pl', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageSl), + value: 'sl', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languagePt), + value: 'pt', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageIt), + value: 'it', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageZh), + value: 'zh', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageSv), + value: 'sv', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageNl), + value: 'nl', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageSk), + value: 'sk', + ), + RadioListTile( + title: Text(context.l10n.appSettings_languageBg), + value: 'bg', + ), + ], + ), + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(context.l10n.common_close), + ), + ], + ), + ); + } + void _showTimeFilterDialog(BuildContext context, AppSettingsService settingsService) { showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Map Time Filter'), + title: Text(context.l10n.appSettings_mapTimeFilter), content: RadioGroup( groupValue: settingsService.settings.mapTimeFilterHours, onChanged: (value) { @@ -448,34 +577,34 @@ class AppSettingsScreen extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, children: [ - const Text('Show nodes discovered within:'), + Text(context.l10n.appSettings_showNodesDiscoveredWithin), const SizedBox(height: 16), ListTile( - title: const Text('All time'), + title: Text(context.l10n.appSettings_allTime), leading: Radio( value: 0, ), ), ListTile( - title: const Text('Last hour'), + title: Text(context.l10n.appSettings_lastHour), leading: Radio( value: 1, ), ), ListTile( - title: const Text('Last 6 hours'), + title: Text(context.l10n.appSettings_last6Hours), leading: Radio( value: 6, ), ), ListTile( - title: const Text('Last 24 hours'), + title: Text(context.l10n.appSettings_last24Hours), leading: Radio( value: 24, ), ), ListTile( - title: const Text('Last week'), + title: Text(context.l10n.appSettings_lastWeek), leading: Radio( value: 168, ), @@ -486,7 +615,7 @@ class AppSettingsScreen extends StatelessWidget { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Close'), + child: Text(context.l10n.common_close), ), ], ), @@ -498,17 +627,17 @@ class AppSettingsScreen extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( - 'Debug', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + context.l10n.appSettings_debugCard, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), SwitchListTile( secondary: const Icon(Icons.bug_report_outlined), - title: const Text('App Debug Logging'), - subtitle: const Text('Log app debug messages for troubleshooting'), + title: Text(context.l10n.appSettings_appDebugLogging), + subtitle: Text(context.l10n.appSettings_appDebugLoggingSubtitle), value: settingsService.settings.appDebugLogEnabled, onChanged: (value) async { await settingsService.setAppDebugLogEnabled(value); @@ -516,8 +645,8 @@ class AppSettingsScreen extends StatelessWidget { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(value - ? 'App debug logging enabled' - : 'App debug logging disabled'), + ? context.l10n.appSettings_appDebugLoggingEnabled + : context.l10n.appSettings_appDebugLoggingDisabled), duration: const Duration(seconds: 2), ), ); diff --git a/lib/screens/ble_debug_log_screen.dart b/lib/screens/ble_debug_log_screen.dart index 6072201..1931403 100644 --- a/lib/screens/ble_debug_log_screen.dart +++ b/lib/screens/ble_debug_log_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter/services.dart'; +import '../l10n/l10n.dart'; import '../services/ble_debug_log_service.dart'; import '../connector/meshcore_protocol.dart'; @@ -26,10 +27,10 @@ class _BleDebugLogScreenState extends State { final hasEntries = showingFrames ? entries.isNotEmpty : rawEntries.isNotEmpty; return Scaffold( appBar: AppBar( - title: const Text('BLE Debug Log'), + title: Text(context.l10n.debugLog_bleTitle), actions: [ IconButton( - tooltip: 'Copy log', + tooltip: context.l10n.debugLog_copyLog, icon: const Icon(Icons.copy), onPressed: hasEntries ? () async { @@ -43,13 +44,13 @@ class _BleDebugLogScreenState extends State { await Clipboard.setData(ClipboardData(text: text)); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('BLE log copied')), + SnackBar(content: Text(context.l10n.debugLog_bleCopied)), ); } : null, ), IconButton( - tooltip: 'Clear log', + tooltip: context.l10n.debugLog_clearLog, icon: const Icon(Icons.delete_outline), onPressed: hasEntries ? () { @@ -66,9 +67,9 @@ class _BleDebugLogScreenState extends State { Padding( padding: const EdgeInsets.fromLTRB(16, 12, 16, 0), child: SegmentedButton<_BleLogView>( - segments: const [ - ButtonSegment(value: _BleLogView.frames, label: Text('Frames')), - ButtonSegment(value: _BleLogView.rawLogRx, label: Text('Raw Log-RX')), + segments: [ + ButtonSegment(value: _BleLogView.frames, label: Text(context.l10n.debugLog_frames)), + ButtonSegment(value: _BleLogView.rawLogRx, label: Text(context.l10n.debugLog_rawLogRx)), ], selected: {_view}, onSelectionChanged: (selection) { @@ -113,8 +114,8 @@ class _BleDebugLogScreenState extends State { ); }, ) - : const Center( - child: Text('No BLE activity yet'), + : Center( + child: Text(context.l10n.debugLog_noBleActivity), ), ), ], @@ -136,7 +137,7 @@ class _BleDebugLogScreenState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Close'), + child: Text(context.l10n.common_close), ), ], ), diff --git a/lib/screens/channel_chat_screen.dart b/lib/screens/channel_chat_screen.dart index 0a5484e..4664843 100644 --- a/lib/screens/channel_chat_screen.dart +++ b/lib/screens/channel_chat_screen.dart @@ -9,6 +9,7 @@ import 'package:provider/provider.dart'; import '../connector/meshcore_connector.dart'; import '../connector/meshcore_protocol.dart'; import '../helpers/utf8_length_limiter.dart'; +import '../l10n/l10n.dart'; import '../models/channel.dart'; import '../models/channel_message.dart'; import '../utils/emoji_utils.dart'; @@ -84,9 +85,9 @@ class _ChannelChatScreenState extends State { final key = _messageKeys[messageId]; if (key == null) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Original message not found'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(context.l10n.chat_originalMessageNotFound), + duration: const Duration(seconds: 2), ), ); return; @@ -120,7 +121,7 @@ class _ChannelChatScreenState extends State { children: [ Text( widget.channel.name.isEmpty - ? 'Channel ${widget.channel.index}' + ? context.l10n.channels_channelIndex(widget.channel.index) : widget.channel.name, style: const TextStyle(fontSize: 16), ), @@ -128,9 +129,9 @@ class _ChannelChatScreenState extends State { builder: (context, connector, _) { final unreadCount = connector.getUnreadCountForChannelIndex(widget.channel.index); - final privacy = widget.channel.isPublicChannel ? 'Public' : 'Private'; + final privacy = widget.channel.isPublicChannel ? context.l10n.channels_public : context.l10n.channels_private; return Text( - '$privacy • Unread: $unreadCount', + '$privacy • ${context.l10n.chat_unread(unreadCount)}', overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 12), ); @@ -170,7 +171,7 @@ class _ChannelChatScreenState extends State { ), const SizedBox(height: 16), Text( - 'No messages yet', + context.l10n.chat_noMessages, style: TextStyle( fontSize: 16, color: Colors.grey[600], @@ -178,7 +179,7 @@ class _ChannelChatScreenState extends State { ), const SizedBox(height: 8), Text( - 'Send a message to get started', + context.l10n.chat_sendMessageToStart, style: TextStyle( fontSize: 14, color: Colors.grey[500], @@ -372,7 +373,7 @@ class _ChannelChatScreenState extends State { children: [ Icon(Icons.location_on_outlined, size: 14, color: previewTextColor), const SizedBox(width: 4), - Text('Location', style: TextStyle(fontSize: 12, color: previewTextColor)), + Text(context.l10n.chat_location, style: TextStyle(fontSize: 12, color: previewTextColor)), ], ); } else { @@ -406,7 +407,7 @@ class _ChannelChatScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Reply to ${message.replyToSenderName}', + context.l10n.chat_replyTo(message.replyToSenderName ?? ''), style: TextStyle( fontSize: 11, fontWeight: FontWeight.bold, @@ -515,7 +516,7 @@ class _ChannelChatScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'POI Shared', + context.l10n.chat_poiShared, style: TextStyle( color: textColor, fontWeight: FontWeight.w600, @@ -623,7 +624,7 @@ class _ChannelChatScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Replying to ${message.senderName}', + context.l10n.chat_replyingTo(message.senderName), style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, @@ -678,7 +679,7 @@ class _ChannelChatScreenState extends State { IconButton( icon: const Icon(Icons.gif_box), onPressed: () => _showGifPicker(context), - tooltip: 'Send GIF', + tooltip: context.l10n.chat_sendGif, ), Expanded( child: ValueListenableBuilder( @@ -714,7 +715,7 @@ class _ChannelChatScreenState extends State { Utf8LengthLimitingTextInputFormatter(maxBytes), ], decoration: InputDecoration( - hintText: 'Type a message...', + hintText: context.l10n.chat_typeMessage, border: OutlineInputBorder( borderRadius: BorderRadius.circular(24), ), @@ -757,7 +758,7 @@ class _ChannelChatScreenState extends State { final maxBytes = maxChannelMessageBytes(connector.selfName); if (utf8.encode(messageText).length > maxBytes) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Message too long (max $maxBytes bytes).')), + SnackBar(content: Text(context.l10n.chat_messageTooLong(maxBytes))), ); return; } @@ -796,7 +797,7 @@ class _ChannelChatScreenState extends State { children: [ ListTile( leading: const Icon(Icons.reply), - title: const Text('Reply'), + title: Text(context.l10n.chat_reply), onTap: () { Navigator.pop(sheetContext); _setReplyingTo(message); @@ -804,7 +805,7 @@ class _ChannelChatScreenState extends State { ), ListTile( leading: const Icon(Icons.add_reaction_outlined), - title: const Text('Add Reaction'), + title: Text(context.l10n.chat_addReaction), onTap: () { Navigator.pop(sheetContext); _showEmojiPicker(message); @@ -812,7 +813,7 @@ class _ChannelChatScreenState extends State { ), ListTile( leading: const Icon(Icons.copy), - title: const Text('Copy'), + title: Text(context.l10n.common_copy), onTap: () { Navigator.pop(sheetContext); _copyMessageText(message.text); @@ -820,7 +821,7 @@ class _ChannelChatScreenState extends State { ), ListTile( leading: const Icon(Icons.delete_outline), - title: const Text('Delete'), + title: Text(context.l10n.common_delete), onTap: () async { Navigator.pop(sheetContext); await _deleteMessage(message); @@ -828,7 +829,7 @@ class _ChannelChatScreenState extends State { ), ListTile( leading: const Icon(Icons.close), - title: const Text('Cancel'), + title: Text(context.l10n.common_cancel), onTap: () => Navigator.pop(sheetContext), ), ], @@ -860,7 +861,7 @@ class _ChannelChatScreenState extends State { void _copyMessageText(String text) { Clipboard.setData(ClipboardData(text: text)); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Message copied')), + SnackBar(content: Text(context.l10n.chat_messageCopied)), ); } @@ -868,7 +869,7 @@ class _ChannelChatScreenState extends State { await context.read().deleteChannelMessage(message); if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Message deleted')), + SnackBar(content: Text(context.l10n.chat_messageDeleted)), ); } diff --git a/lib/screens/channel_message_path_screen.dart b/lib/screens/channel_message_path_screen.dart index 46c8283..93d510e 100644 --- a/lib/screens/channel_message_path_screen.dart +++ b/lib/screens/channel_message_path_screen.dart @@ -9,6 +9,8 @@ import 'package:provider/provider.dart'; import '../connector/meshcore_connector.dart'; import '../services/map_tile_cache_service.dart'; import '../connector/meshcore_protocol.dart'; +import '../l10n/app_localizations.dart'; +import '../l10n/l10n.dart'; import '../models/channel_message.dart'; import '../models/contact.dart'; @@ -24,22 +26,24 @@ class ChannelMessagePathScreen extends StatelessWidget { Widget build(BuildContext context) { return Consumer( builder: (context, connector, _) { + final l10n = context.l10n; final primaryPath = _selectPrimaryPath(message.pathBytes, message.pathVariants); - final hops = _buildPathHops(primaryPath, connector.contacts); + final hops = _buildPathHops(primaryPath, connector.contacts, l10n); final hasHopDetails = primaryPath.isNotEmpty; final observedLabel = _formatObservedHops( primaryPath.length, message.pathLength, + l10n, ); final extraPaths = _otherPaths(primaryPath, message.pathVariants); return Scaffold( appBar: AppBar( - title: const Text('Packet Path'), + title: Text(l10n.channelPath_title), actions: [ IconButton( icon: const Icon(Icons.map_outlined), - tooltip: 'View map', + tooltip: l10n.channelPath_viewMap, onPressed: hasHopDetails ? () { _openPathMap(context); @@ -57,7 +61,7 @@ class ChannelMessagePathScreen extends StatelessWidget { const SizedBox(height: 16), if (extraPaths.isNotEmpty) ...[ Text( - 'Other Observed Paths', + l10n.channelPath_otherObservedPaths, style: Theme.of(context).textTheme.titleSmall, ), const SizedBox(height: 8), @@ -65,17 +69,17 @@ class ChannelMessagePathScreen extends StatelessWidget { const SizedBox(height: 16), ], Text( - 'Repeater Hops', + l10n.channelPath_repeaterHops, style: Theme.of(context).textTheme.titleSmall, ), const SizedBox(height: 8), if (!hasHopDetails) - const Text( - 'Hop details are not provided for this packet.', - style: TextStyle(color: Colors.grey), + Text( + l10n.channelPath_noHopDetails, + style: const TextStyle(color: Colors.grey), ) else - ..._buildHopTiles(hops), + ..._buildHopTiles(context, hops), ], ), ), @@ -88,6 +92,7 @@ class ChannelMessagePathScreen extends StatelessWidget { BuildContext context, { String? observedLabel, }) { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(12), @@ -95,16 +100,16 @@ class ChannelMessagePathScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Message Details', + l10n.channelPath_messageDetails, style: Theme.of(context).textTheme.titleSmall, ), const SizedBox(height: 8), - _buildDetailRow('Sender', message.senderName), - _buildDetailRow('Time', _formatTime(message.timestamp)), + _buildDetailRow(l10n.channelPath_senderLabel, message.senderName), + _buildDetailRow(l10n.channelPath_timeLabel, _formatTime(message.timestamp, l10n)), if (message.repeatCount > 0) - _buildDetailRow('Repeats', message.repeatCount.toString()), - _buildDetailRow('Path', _formatPathLabel(message.pathLength)), - if (observedLabel != null) _buildDetailRow('Observed', observedLabel), + _buildDetailRow(l10n.channelPath_repeatsLabel, message.repeatCount.toString()), + _buildDetailRow(l10n.channelPath_pathLabelTitle, _formatPathLabel(message.pathLength, l10n)), + if (observedLabel != null) _buildDetailRow(l10n.channelPath_observedLabel, observedLabel), ], ), ), @@ -115,6 +120,7 @@ class ChannelMessagePathScreen extends StatelessWidget { BuildContext context, List variants, ) { + final l10n = context.l10n; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -124,7 +130,10 @@ class ChannelMessagePathScreen extends StatelessWidget { child: ListTile( dense: true, title: Text( - 'Observed path ${i + 1} • ${_formatHopCount(variants[i].length)}', + l10n.channelPath_observedPathTitle( + i + 1, + _formatHopCount(variants[i].length, l10n), + ), ), subtitle: Text(_formatPathPrefixes(variants[i])), trailing: const Icon(Icons.map_outlined, size: 20), @@ -135,7 +144,8 @@ class ChannelMessagePathScreen extends StatelessWidget { ); } - List _buildHopTiles(List<_PathHop> hops) { + List _buildHopTiles(BuildContext context, List<_PathHop> hops) { + final l10n = context.l10n; return [ for (final hop in hops) Card( @@ -154,45 +164,52 @@ class ChannelMessagePathScreen extends StatelessWidget { hop.hasLocation ? '${hop.position!.latitude.toStringAsFixed(5)}, ' '${hop.position!.longitude.toStringAsFixed(5)}' - : 'No location data', + : l10n.channelPath_noLocationData, ), ), ), ]; } - String _formatTime(DateTime time) { + String _formatTime(DateTime time, AppLocalizations l10n) { final now = DateTime.now(); final diff = now.difference(time); if (diff.inDays > 0) { - return '${time.day}/${time.month} ' + final timeLabel = '${time.hour}:${time.minute.toString().padLeft(2, '0')}'; + return l10n.channelPath_timeWithDate(time.day, time.month, timeLabel); } - return '${time.hour}:${time.minute.toString().padLeft(2, '0')}'; + return l10n.channelPath_timeOnly( + '${time.hour}:${time.minute.toString().padLeft(2, '0')}', + ); } - String _formatPathLabel(int? pathLength) { - if (pathLength == null) return 'Unknown'; - if (pathLength < 0) return 'Flood'; - if (pathLength == 0) return 'Direct'; - return '$pathLength hops'; + String _formatPathLabel(int? pathLength, AppLocalizations l10n) { + if (pathLength == null) return l10n.channelPath_unknownPath; + if (pathLength < 0) return l10n.channelPath_floodPath; + if (pathLength == 0) return l10n.channelPath_directPath; + return l10n.chat_hopsCount(pathLength); } - String? _formatObservedHops(int observedCount, int? pathLength) { + String? _formatObservedHops( + int observedCount, + int? pathLength, + AppLocalizations l10n, + ) { if (observedCount <= 0 && (pathLength == null || pathLength <= 0)) { return null; } if (pathLength == null || pathLength < 0) { - return observedCount > 0 ? '$observedCount hops' : null; + return observedCount > 0 ? l10n.chat_hopsCount(observedCount) : null; } if (observedCount == 0) { - return '0 of $pathLength hops'; + return l10n.channelPath_observedZeroOf(pathLength); } if (observedCount == pathLength) { - return '$observedCount hops'; + return l10n.chat_hopsCount(observedCount); } - return '$observedCount of $pathLength hops'; + return l10n.channelPath_observedSomeOf(observedCount, pathLength); } Widget _buildDetailRow(String label, String value) { @@ -274,7 +291,7 @@ class _ChannelMessagePathMapScreenState extends State hop.hasLocation) .map((hop) => hop.position!) @@ -297,7 +314,7 @@ class _ChannelMessagePathMapScreenState extends State onSelected, ) { + final l10n = context.l10n; final selectedPath = paths[selectedIndex]; final label = selectedPath.isPrimary - ? 'Path ${selectedIndex + 1} (Primary)' - : 'Path ${selectedIndex + 1}'; + ? l10n.channelPath_primaryPath(selectedIndex + 1) + : l10n.channelPath_pathLabel(selectedIndex + 1); return Positioned( left: 16, right: 16, @@ -383,9 +401,9 @@ class _ChannelMessagePathMapScreenState extends State hops) { + final l10n = context.l10n; final maxHeight = MediaQuery.of(context).size.height * 0.35; final estimatedHeight = 72.0 + (hops.length * 56.0); final cardHeight = max(96.0, min(maxHeight, estimatedHeight)); @@ -471,18 +493,18 @@ class _ChannelMessagePathMapScreenState extends State position != null; String get displayLabel { final prefixLabel = _formatPrefix(prefix); - return '($prefixLabel) ${_resolveName(contact)}'; + return '($prefixLabel) ${_resolveName(contact, l10n)}'; } } @@ -549,7 +573,11 @@ class _ObservedPath { }); } -List<_PathHop> _buildPathHops(Uint8List pathBytes, List contacts) { +List<_PathHop> _buildPathHops( + Uint8List pathBytes, + List contacts, + AppLocalizations l10n, +) { final hops = <_PathHop>[]; for (var i = 0; i < pathBytes.length; i++) { final prefix = pathBytes[i]; @@ -560,6 +588,7 @@ List<_PathHop> _buildPathHops(Uint8List pathBytes, List contacts) { prefix: prefix, contact: contact, position: _resolvePosition(contact), + l10n: l10n, ), ); } @@ -612,15 +641,15 @@ String _formatPathPrefixes(Uint8List pathBytes) { .join(','); } -String _formatHopCount(int count) { - return '$count ${count == 1 ? 'hop' : 'hops'}'; +String _formatHopCount(int count, AppLocalizations l10n) { + return l10n.chat_hopsCount(count); } -String _resolveName(Contact? contact) { - if (contact == null) return 'Unknown Repeater'; +String _resolveName(Contact? contact, AppLocalizations l10n) { + if (contact == null) return l10n.channelPath_unknownRepeater; final name = contact.name.trim(); if (name.isEmpty || name.toLowerCase() == 'unknown') { - return 'Unknown Repeater'; + return l10n.channelPath_unknownRepeater; } return name; } diff --git a/lib/screens/channels_screen.dart b/lib/screens/channels_screen.dart index d97cfbf..a652d00 100644 --- a/lib/screens/channels_screen.dart +++ b/lib/screens/channels_screen.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../connector/meshcore_connector.dart'; +import '../l10n/l10n.dart'; import '../models/channel.dart'; import '../utils/dialog_utils.dart'; import '../utils/disconnect_navigation_mixin.dart'; @@ -77,18 +78,18 @@ class _ChannelsScreenState extends State child: Scaffold( appBar: AppBar( leading: BatteryIndicator(connector: connector), - title: const Text('Channels'), + title: Text(context.l10n.channels_title), centerTitle: true, automaticallyImplyLeading: false, actions: [ IconButton( icon: const Icon(Icons.bluetooth_disabled), - tooltip: 'Disconnect', + tooltip: context.l10n.common_disconnect, onPressed: () => _disconnect(context), ), IconButton( icon: const Icon(Icons.tune), - tooltip: 'Settings', + tooltip: context.l10n.common_settings, onPressed: () => Navigator.push( context, MaterialPageRoute(builder: (context) => const SettingsScreen()), @@ -114,11 +115,11 @@ class _ChannelsScreenState extends State height: MediaQuery.of(context).size.height - 200, child: EmptyState( icon: Icons.tag, - title: 'No channels configured', + title: context.l10n.channels_noChannelsConfigured, action: FilledButton.icon( onPressed: () => _addPublicChannel(context, connector), icon: const Icon(Icons.public), - label: const Text('Add Public Channel'), + label: Text(context.l10n.channels_addPublicChannel), ), ), ), @@ -135,7 +136,7 @@ class _ChannelsScreenState extends State child: TextField( controller: _searchController, decoration: InputDecoration( - hintText: 'Search channels...', + hintText: context.l10n.channels_searchChannels, prefixIcon: const Icon(Icons.search), suffixIcon: Row( mainAxisSize: MainAxisSize.min, @@ -183,7 +184,7 @@ class _ChannelsScreenState extends State Icon(Icons.search_off, size: 64, color: Colors.grey[400]), const SizedBox(height: 16), Text( - 'No channels found', + context.l10n.channels_noChannelsFound, style: TextStyle(fontSize: 16, color: Colors.grey[600]), ), ], @@ -289,15 +290,15 @@ class _ChannelsScreenState extends State ), ), title: Text( - channel.name.isEmpty ? 'Channel ${channel.index}' : channel.name, + channel.name.isEmpty ? context.l10n.channels_channelIndex(channel.index) : channel.name, style: const TextStyle(fontWeight: FontWeight.w500), ), subtitle: Text( channel.name.startsWith('#') - ? 'Hashtag channel' + ? context.l10n.channels_hashtagChannel : channel.isPublicChannel - ? 'Public channel' - : 'Private channel', + ? context.l10n.channels_publicChannel + : context.l10n.channels_privateChannel, ), trailing: Row( mainAxisSize: MainAxisSize.min, @@ -346,7 +347,7 @@ class _ChannelsScreenState extends State children: [ ListTile( leading: const Icon(Icons.edit_outlined), - title: const Text('Edit channel'), + title: Text(context.l10n.channels_editChannel), onTap: () async { Navigator.pop(context); await Future.delayed(const Duration(milliseconds: 100)); @@ -357,7 +358,7 @@ class _ChannelsScreenState extends State ), ListTile( leading: const Icon(Icons.delete_outline, color: Colors.red), - title: const Text('Delete channel', style: TextStyle(color: Colors.red)), + title: Text(context.l10n.channels_deleteChannel, style: const TextStyle(color: Colors.red)), onTap: () async { Navigator.pop(context); await Future.delayed(const Duration(milliseconds: 100)); @@ -406,28 +407,29 @@ class _ChannelsScreenState extends State const actionSortUnread = 3; return SortFilterMenu( + tooltip: context.l10n.listFilter_tooltip, sections: [ SortFilterMenuSection( - title: 'Sort by', + title: context.l10n.channels_sortBy, options: [ SortFilterMenuOption( value: actionSortManual, - label: 'Manual', + label: context.l10n.channels_sortManual, checked: _sortOption == ChannelSortOption.manual, ), SortFilterMenuOption( value: actionSortName, - label: 'A-Z', + label: context.l10n.channels_sortAZ, checked: _sortOption == ChannelSortOption.name, ), SortFilterMenuOption( value: actionSortLatest, - label: 'Latest messages', + label: context.l10n.channels_sortLatestMessages, checked: _sortOption == ChannelSortOption.latestMessages, ), SortFilterMenuOption( value: actionSortUnread, - label: 'Unread', + label: context.l10n.channels_sortUnread, checked: _sortOption == ChannelSortOption.unread, ), ], @@ -503,7 +505,7 @@ class _ChannelsScreenState extends State } String _normalizeChannelName(Channel channel) { - if (channel.name.isEmpty) return 'Channel ${channel.index}'; + if (channel.name.isEmpty) return 'Channel ${channel.index}'; // Fallback for sorting final trimmed = channel.name.trim(); if (trimmed.startsWith('#') && trimmed.length > 1) { return trimmed.substring(1); @@ -521,9 +523,9 @@ class _ChannelsScreenState extends State showDialog( context: context, - builder: (context) => StatefulBuilder( - builder: (context, setDialogState) => AlertDialog( - title: const Text('Add Channel'), + builder: (dialogContext) => StatefulBuilder( + builder: (dialogContext, setDialogState) => AlertDialog( + title: Text(dialogContext.l10n.channels_addChannel), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, @@ -531,14 +533,14 @@ class _ChannelsScreenState extends State children: [ DropdownButtonFormField( initialValue: selectedIndex, - decoration: const InputDecoration( - labelText: 'Channel Index', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: dialogContext.l10n.channels_channelIndexLabel, + border: const OutlineInputBorder(), ), items: List.generate(maxChannels, (i) => i) .map((i) => DropdownMenuItem( value: i, - child: Text('Channel $i'), + child: Text(dialogContext.l10n.channels_channelIndex(i)), )) .toList(), onChanged: (value) { @@ -550,16 +552,16 @@ class _ChannelsScreenState extends State const SizedBox(height: 16), TextField( controller: nameController, - decoration: const InputDecoration( - labelText: 'Channel Name', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: dialogContext.l10n.channels_channelName, + border: const OutlineInputBorder(), ), maxLength: 31, ), const SizedBox(height: 8), CheckboxListTile( - title: const Text('Use Public Channel'), - subtitle: const Text('Standard public PSK'), + title: Text(dialogContext.l10n.channels_usePublicChannel), + subtitle: Text(dialogContext.l10n.channels_standardPublicPsk), value: usePublicPsk, onChanged: (value) { setDialogState(() { @@ -578,11 +580,11 @@ class _ChannelsScreenState extends State TextField( controller: pskController, decoration: InputDecoration( - labelText: 'PSK (Hex)', + labelText: dialogContext.l10n.channels_pskHex, border: const OutlineInputBorder(), suffixIcon: IconButton( icon: const Icon(Icons.casino), - tooltip: 'Generate random PSK', + tooltip: dialogContext.l10n.channels_generateRandomPsk, onPressed: () { final random = Random.secure(); final bytes = Uint8List(16); @@ -600,8 +602,8 @@ class _ChannelsScreenState extends State ), actions: [ TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + onPressed: () => Navigator.pop(dialogContext), + child: Text(dialogContext.l10n.common_cancel), ), FilledButton( onPressed: () { @@ -611,8 +613,8 @@ class _ChannelsScreenState extends State : pskController.text.trim(); if (name.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Please enter a channel name')), + ScaffoldMessenger.of(dialogContext).showSnackBar( + SnackBar(content: Text(dialogContext.l10n.channels_enterChannelName)), ); return; } @@ -621,21 +623,21 @@ class _ChannelsScreenState extends State try { psk = Channel.parsePskHex(pskHex); } on FormatException { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('PSK must be 32 hex characters')), + ScaffoldMessenger.of(dialogContext).showSnackBar( + SnackBar(content: Text(dialogContext.l10n.channels_pskMustBe32Hex)), ); return; } - Navigator.pop(context); + Navigator.pop(dialogContext); connector.setChannel(selectedIndex, name, psk); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Channel "$name" added')), + SnackBar(content: Text(context.l10n.channels_channelAdded(name))), ); } }, - child: const Text('Add'), + child: Text(dialogContext.l10n.common_add), ), ], ), @@ -654,18 +656,18 @@ class _ChannelsScreenState extends State showDialog( context: context, - builder: (context) => StatefulBuilder( - builder: (context, setState) => AlertDialog( - title: Text('Edit Channel ${channel.index}'), + builder: (dialogContext) => StatefulBuilder( + builder: (dialogContext, setState) => AlertDialog( + title: Text(dialogContext.l10n.channels_editChannelTitle(channel.index)), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: nameController, - decoration: const InputDecoration( - labelText: 'Channel Name', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: dialogContext.l10n.channels_channelName, + border: const OutlineInputBorder(), ), maxLength: 31, ), @@ -673,11 +675,11 @@ class _ChannelsScreenState extends State TextField( controller: pskController, decoration: InputDecoration( - labelText: 'PSK (Hex)', + labelText: dialogContext.l10n.channels_pskHex, border: const OutlineInputBorder(), suffixIcon: IconButton( icon: const Icon(Icons.casino), - tooltip: 'Generate random PSK', + tooltip: dialogContext.l10n.channels_generateRandomPsk, onPressed: () { final random = Random.secure(); final bytes = Uint8List(16); @@ -692,7 +694,7 @@ class _ChannelsScreenState extends State const SizedBox(height: 16), SwitchListTile( contentPadding: EdgeInsets.zero, - title: const Text('SMAZ compression'), + title: Text(dialogContext.l10n.channels_smazCompression), value: smazEnabled, onChanged: (value) => setState(() => smazEnabled = value), ), @@ -701,8 +703,8 @@ class _ChannelsScreenState extends State ), actions: [ TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + onPressed: () => Navigator.pop(dialogContext), + child: Text(dialogContext.l10n.common_cancel), ), FilledButton( onPressed: () { @@ -713,20 +715,20 @@ class _ChannelsScreenState extends State try { psk = Channel.parsePskHex(pskHex); } on FormatException { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('PSK must be 32 hex characters')), + ScaffoldMessenger.of(dialogContext).showSnackBar( + SnackBar(content: Text(dialogContext.l10n.channels_pskMustBe32Hex)), ); return; } - Navigator.pop(context); + Navigator.pop(dialogContext); connector.setChannel(channel.index, name, psk); connector.setChannelSmazEnabled(channel.index, smazEnabled); ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Channel "$name" updated')), + SnackBar(content: Text(context.l10n.channels_channelUpdated(name))), ); }, - child: const Text('Save'), + child: Text(dialogContext.l10n.common_save), ), ], ), @@ -741,23 +743,23 @@ class _ChannelsScreenState extends State ) { showDialog( context: context, - builder: (context) => AlertDialog( - title: const Text('Delete Channel'), - content: Text('Delete "${channel.name}"? This cannot be undone.'), + builder: (dialogContext) => AlertDialog( + title: Text(dialogContext.l10n.channels_deleteChannel), + content: Text(dialogContext.l10n.channels_deleteChannelConfirm(channel.name)), actions: [ TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + onPressed: () => Navigator.pop(dialogContext), + child: Text(dialogContext.l10n.common_cancel), ), TextButton( onPressed: () { - Navigator.pop(context); + Navigator.pop(dialogContext); connector.deleteChannel(channel.index); ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Channel "${channel.name}" deleted')), + SnackBar(content: Text(context.l10n.channels_channelDeleted(channel.name))), ); }, - child: const Text('Delete', style: TextStyle(color: Colors.red)), + child: Text(dialogContext.l10n.common_delete, style: const TextStyle(color: Colors.red)), ), ], ), @@ -768,7 +770,7 @@ class _ChannelsScreenState extends State final psk = Channel.parsePskHex(Channel.publicChannelPsk); connector.setChannel(0, 'Public', psk); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Public channel added')), + SnackBar(content: Text(context.l10n.channels_publicChannelAdded)), ); } diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart index ce4c3e1..5764bc8 100644 --- a/lib/screens/chat_screen.dart +++ b/lib/screens/chat_screen.dart @@ -23,6 +23,7 @@ import '../widgets/gif_message.dart'; import '../widgets/gif_picker.dart'; import '../widgets/path_selection_dialog.dart'; import '../utils/app_logger.dart'; +import '../l10n/l10n.dart'; class ChatScreen extends StatefulWidget { final Contact contact; @@ -67,7 +68,7 @@ class _ChatScreenState extends State { builder: (context, pathService, connector, _) { final contact = _resolveContact(connector); final unreadCount = connector.getUnreadCountForContactKey(widget.contact.publicKeyHex); - final unreadLabel = 'Unread: $unreadCount'; + final unreadLabel = context.l10n.chat_unread(unreadCount); final pathLabel = _currentPathLabel(contact); // Show path details if we have path data (from device or override) @@ -106,7 +107,7 @@ class _ChatScreenState extends State { return PopupMenuButton( icon: Icon(isFloodMode ? Icons.waves : Icons.route), - tooltip: 'Routing mode', + tooltip: context.l10n.chat_routingMode, onSelected: (mode) async { if (mode == 'flood') { await connector.setPathOverride(contact, pathLen: -1); @@ -122,7 +123,7 @@ class _ChatScreenState extends State { Icon(Icons.auto_mode, size: 20, color: !isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Auto (use saved path)', + context.l10n.chat_autoUseSavedPath, style: TextStyle( fontWeight: !isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -137,7 +138,7 @@ class _ChatScreenState extends State { Icon(Icons.waves, size: 20, color: isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Force Flood Mode', + context.l10n.chat_forceFloodMode, style: TextStyle( fontWeight: isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -151,7 +152,7 @@ class _ChatScreenState extends State { ), IconButton( icon: const Icon(Icons.timeline), - tooltip: 'Path management', + tooltip: context.l10n.chat_pathManagement, onPressed: () => _showPathHistory(context), ), IconButton( @@ -186,12 +187,12 @@ class _ChatScreenState extends State { Icon(Icons.chat_bubble_outline, size: 64, color: Colors.grey[400]), const SizedBox(height: 16), Text( - 'No messages yet', + context.l10n.chat_noMessages, style: TextStyle(fontSize: 16, color: Colors.grey[600]), ), const SizedBox(height: 8), Text( - 'Send a message to ${widget.contact.name}', + context.l10n.chat_sendMessageTo(widget.contact.name), style: TextStyle(fontSize: 14, color: Colors.grey[500]), ), ], @@ -244,7 +245,7 @@ class _ChatScreenState extends State { IconButton( icon: const Icon(Icons.gif_box), onPressed: () => _showGifPicker(context), - tooltip: 'Send GIF', + tooltip: context.l10n.chat_sendGif, ), Expanded( child: ValueListenableBuilder( @@ -278,10 +279,10 @@ class _ChatScreenState extends State { inputFormatters: [ Utf8LengthLimitingTextInputFormatter(maxBytes), ], - decoration: const InputDecoration( - hintText: 'Type a message...', - border: OutlineInputBorder(), - contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: InputDecoration( + hintText: context.l10n.chat_typeMessage, + border: const OutlineInputBorder(), + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), textInputAction: TextInputAction.send, onSubmitted: (_) => _sendMessage(connector), @@ -325,7 +326,7 @@ class _ChatScreenState extends State { final maxBytes = maxContactMessageBytes(); if (utf8.encode(text).length > maxBytes) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Message too long (max $maxBytes bytes).')), + SnackBar(content: Text(context.l10n.chat_messageTooLong(maxBytes))), ); return; } @@ -357,11 +358,11 @@ class _ChatScreenState extends State { builder: (context, pathService, _) { final paths = pathService.getRecentPaths(widget.contact.publicKeyHex); return AlertDialog( - title: const Row( + title: Row( children: [ - Icon(Icons.timeline), - SizedBox(width: 8), - Text('Path Management'), + const Icon(Icons.timeline), + const SizedBox(width: 8), + Text(context.l10n.chat_pathManagement), ], ), content: SingleChildScrollView( @@ -370,9 +371,9 @@ class _ChatScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (paths.isNotEmpty) ...[ - const Text( - 'Recent ACK Paths (tap to use):', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), + Text( + context.l10n.chat_recentAckPaths, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12), ), if (paths.length >= 100) ...[ const SizedBox(height: 8), @@ -383,9 +384,9 @@ class _ChatScreenState extends State { color: Colors.amber[100], borderRadius: BorderRadius.circular(8), ), - child: const Text( - 'Path history is full. Remove entries to add new ones.', - style: TextStyle(fontSize: 12), + child: Text( + context.l10n.chat_pathHistoryFull, + style: const TextStyle(fontSize: 12), ), ), ], @@ -404,11 +405,11 @@ class _ChatScreenState extends State { ), ), title: Text( - '${path.hopCount} ${path.hopCount == 1 ? 'hop' : 'hops'}', + '${path.hopCount} ${path.hopCount == 1 ? context.l10n.chat_hopSingular : context.l10n.chat_hopPlural}', style: const TextStyle(fontSize: 14), ), subtitle: Text( - '${(path.tripTimeMs / 1000).toStringAsFixed(2)}s • ${_formatRelativeTime(path.timestamp)} • ${path.successCount} successes', + '${(path.tripTimeMs / 1000).toStringAsFixed(2)}s • ${_formatRelativeTime(path.timestamp)} • ${path.successCount} ${context.l10n.chat_successes}', style: const TextStyle(fontSize: 11), ), trailing: Row( @@ -416,7 +417,7 @@ class _ChatScreenState extends State { children: [ IconButton( icon: const Icon(Icons.close, size: 16), - tooltip: 'Remove path', + tooltip: context.l10n.chat_removePath, onPressed: () async { await pathService.removePathRecord( widget.contact.publicKeyHex, @@ -433,9 +434,9 @@ class _ChatScreenState extends State { onTap: () async { if (path.pathBytes.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Path details not available yet. Try sending a message to refresh.'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(context.l10n.chat_pathDetailsNotAvailable), + duration: const Duration(seconds: 2), ), ); return; @@ -465,13 +466,13 @@ class _ChatScreenState extends State { }), const Divider(), ] else ...[ - const Text('No path history yet.\nSend a message to discover paths.'), + Text(context.l10n.chat_noPathHistoryYet), const Divider(), ], const SizedBox(height: 8), - const Text( - 'Path Actions:', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), + Text( + context.l10n.chat_pathActions, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12), ), const SizedBox(height: 8), ListTile( @@ -481,8 +482,8 @@ class _ChatScreenState extends State { backgroundColor: Colors.purple, child: Icon(Icons.edit_road, size: 16), ), - title: const Text('Set Custom Path', style: TextStyle(fontSize: 14)), - subtitle: const Text('Manually specify routing path', style: TextStyle(fontSize: 11)), + title: Text(context.l10n.chat_setCustomPath, style: const TextStyle(fontSize: 14)), + subtitle: Text(context.l10n.chat_setCustomPathSubtitle, style: const TextStyle(fontSize: 11)), onTap: () { Navigator.pop(context); _showCustomPathDialog(context); @@ -495,15 +496,15 @@ class _ChatScreenState extends State { backgroundColor: Colors.orange, child: Icon(Icons.clear_all, size: 16), ), - title: const Text('Clear Path', style: TextStyle(fontSize: 14)), - subtitle: const Text('Force rediscovery on next send', style: TextStyle(fontSize: 11)), + title: Text(context.l10n.chat_clearPath, style: const TextStyle(fontSize: 14)), + subtitle: Text(context.l10n.chat_clearPathSubtitle, style: const TextStyle(fontSize: 11)), onTap: () async { await connector.clearContactPath(widget.contact); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Path cleared. Next message will rediscover route.'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(context.l10n.chat_pathCleared), + duration: const Duration(seconds: 2), ), ); Navigator.pop(context); @@ -516,15 +517,15 @@ class _ChatScreenState extends State { backgroundColor: Colors.blue, child: Icon(Icons.waves, size: 16), ), - title: const Text('Force Flood Mode', style: TextStyle(fontSize: 14)), - subtitle: const Text('Use routing toggle in app bar', style: TextStyle(fontSize: 11)), + title: Text(context.l10n.chat_forceFloodMode, style: const TextStyle(fontSize: 14)), + subtitle: Text(context.l10n.chat_floodModeSubtitle, style: const TextStyle(fontSize: 11)), onTap: () async { await connector.setPathOverride(widget.contact, pathLen: -1); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Flood mode enabled. Toggle back via routing icon in app bar.'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(context.l10n.chat_floodModeEnabled), + duration: const Duration(seconds: 2), ), ); Navigator.pop(context); @@ -536,7 +537,7 @@ class _ChatScreenState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Close'), + child: Text(context.l10n.common_close), ), ], ); @@ -547,18 +548,18 @@ class _ChatScreenState extends State { String _formatRelativeTime(DateTime time) { final diff = DateTime.now().difference(time); - if (diff.inSeconds < 60) return 'Just now'; - if (diff.inMinutes < 60) return '${diff.inMinutes}m ago'; - if (diff.inHours < 24) return '${diff.inHours}h ago'; - return '${diff.inDays}d ago'; + if (diff.inSeconds < 60) return context.l10n.time_justNow; + if (diff.inMinutes < 60) return context.l10n.time_minutesAgo(diff.inMinutes); + if (diff.inHours < 24) return context.l10n.time_hoursAgo(diff.inHours); + return context.l10n.time_daysAgo(diff.inDays); } void _showFullPathDialog(BuildContext context, List pathBytes) { if (pathBytes.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Path details not available yet. Try sending a message to refresh.'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(context.l10n.chat_pathDetailsNotAvailable), + duration: const Duration(seconds: 2), ), ); return; @@ -571,12 +572,12 @@ class _ChatScreenState extends State { showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Full Path'), + title: Text(context.l10n.chat_fullPath), content: SelectableText(formattedPath), actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Close'), + child: Text(context.l10n.common_close), ), ], ), @@ -600,15 +601,15 @@ class _ChatScreenState extends State { String _currentPathLabel(Contact contact) { // Check if user has set a path override if (contact.pathOverride != null) { - if (contact.pathOverride! < 0) return 'Flood (forced)'; - if (contact.pathOverride == 0) return 'Direct (forced)'; - return '${contact.pathOverride} hops (forced)'; + if (contact.pathOverride! < 0) return context.l10n.chat_floodForced; + if (contact.pathOverride == 0) return context.l10n.chat_directForced; + return context.l10n.chat_hopsForced(contact.pathOverride!); } // Use device's path - if (contact.pathLength < 0) return 'Flood (auto)'; - if (contact.pathLength == 0) return 'Direct'; - return '${contact.pathLength} hops'; + if (contact.pathLength < 0) return context.l10n.chat_floodAuto; + if (contact.pathLength == 0) return context.l10n.chat_direct; + return context.l10n.chat_hopsCount(contact.pathLength); } Future _notifyPathSet( @@ -623,12 +624,12 @@ class _ChatScreenState extends State { if (!mounted) return; final status = !connector.isConnected - ? 'Saved locally. Connect to sync.' - : (verified ? 'Device confirmed.' : 'Device not confirmed yet.'); + ? context.l10n.chat_pathSavedLocally + : (verified ? context.l10n.chat_pathDeviceConfirmed : context.l10n.chat_pathDeviceNotConfirmed); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - 'Path set: $hopCount ${hopCount == 1 ? 'hop' : 'hops'} - $status', + context.l10n.chat_pathSetHops(hopCount, status), ), duration: const Duration(seconds: 3), ), @@ -653,19 +654,19 @@ class _ChatScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildInfoRow('Type', contact.typeLabel), - _buildInfoRow('Path', contact.pathLabel), + _buildInfoRow(context.l10n.chat_type, contact.typeLabel), + _buildInfoRow(context.l10n.chat_path, contact.pathLabel), if (contact.hasLocation) _buildInfoRow( - 'Location', + context.l10n.chat_location, '${contact.latitude?.toStringAsFixed(4)}, ${contact.longitude?.toStringAsFixed(4)}', ), - _buildInfoRow('Public Key', '${contact.publicKeyHex.substring(0, 16)}...'), + _buildInfoRow(context.l10n.chat_publicKey, '${contact.publicKeyHex.substring(0, 16)}...'), const Divider(), SwitchListTile( contentPadding: EdgeInsets.zero, - title: const Text('SMAZ compression'), - subtitle: const Text('Compress outgoing messages'), + title: Text(context.l10n.channels_smazCompression), + subtitle: Text(context.l10n.chat_compressOutgoingMessages), value: smazEnabled, onChanged: (value) { connector.setContactSmazEnabled(contact.publicKeyHex, value); @@ -677,7 +678,7 @@ class _ChatScreenState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Close'), + child: Text(context.l10n.common_close), ), ], ); @@ -731,7 +732,7 @@ class _ChatScreenState extends State { context, availableContacts: availableContacts, initialPath: pathForInput.isEmpty ? null : pathForInput, - title: 'Set Custom Path', + title: context.l10n.chat_setCustomPath, currentPathLabel: currentPathLabel, onRefresh: connector.isConnected ? connector.getContacts : null, ); @@ -769,7 +770,7 @@ class _ChatScreenState extends State { .toUpperCase(); final String senderName; if (message.isOutgoing) { - senderName = connector.selfName ?? 'Me'; + senderName = connector.selfName ?? context.l10n.chat_me; } else if (widget.contact.type == advTypeRoom) { senderName = "${contact.name} [$fourByteHex]"; } else { @@ -803,7 +804,7 @@ class _ChatScreenState extends State { children: [ ListTile( leading: const Icon(Icons.add_reaction_outlined), - title: const Text('Add Reaction'), + title: Text(context.l10n.chat_addReaction), onTap: () { Navigator.pop(sheetContext); _showEmojiPicker(message); @@ -811,7 +812,7 @@ class _ChatScreenState extends State { ), ListTile( leading: const Icon(Icons.copy), - title: const Text('Copy'), + title: Text(context.l10n.common_copy), onTap: () { Navigator.pop(sheetContext); _copyMessageText(message.text); @@ -819,7 +820,7 @@ class _ChatScreenState extends State { ), ListTile( leading: const Icon(Icons.delete_outline), - title: const Text('Delete'), + title: Text(context.l10n.common_delete), onTap: () async { Navigator.pop(sheetContext); await _deleteMessage(message); @@ -829,7 +830,7 @@ class _ChatScreenState extends State { message.status == MessageStatus.failed) ListTile( leading: const Icon(Icons.refresh), - title: const Text('Retry'), + title: Text(context.l10n.common_retry), onTap: () { Navigator.pop(sheetContext); _retryMessage(message); @@ -838,7 +839,7 @@ class _ChatScreenState extends State { if (widget.contact.type == advTypeRoom) ListTile( leading: const Icon(Icons.chat), - title: const Text('Open Chat'), + title: Text(context.l10n.contacts_openChat), onTap: () { Navigator.pop(sheetContext); _openChat(context, contact); @@ -846,7 +847,7 @@ class _ChatScreenState extends State { ), ListTile( leading: const Icon(Icons.close), - title: const Text('Cancel'), + title: Text(context.l10n.common_cancel), onTap: () => Navigator.pop(sheetContext), ), ], @@ -858,7 +859,7 @@ class _ChatScreenState extends State { void _copyMessageText(String text) { Clipboard.setData(ClipboardData(text: text)); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Message copied')), + SnackBar(content: Text(context.l10n.chat_messageCopied)), ); } @@ -866,7 +867,7 @@ class _ChatScreenState extends State { await context.read().deleteMessage(message); if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Message deleted')), + SnackBar(content: Text(context.l10n.chat_messageDeleted)), ); } @@ -878,7 +879,7 @@ class _ChatScreenState extends State { message.text, ); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Retrying message')), + SnackBar(content: Text(context.l10n.chat_retryingMessage)), ); } @@ -996,7 +997,7 @@ class _MessageBubble extends StatelessWidget { if (isOutgoing && message.retryCount > 0) ...[ const SizedBox(height: 4), Text( - 'Retry ${message.retryCount}/4', + context.l10n.chat_retryCount(message.retryCount, 4), style: TextStyle( fontSize: 10, color: metaColor, @@ -1106,7 +1107,7 @@ class _MessageBubble extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'POI Shared', + context.l10n.chat_poiShared, style: TextStyle( color: textColor, fontWeight: FontWeight.w600, diff --git a/lib/screens/contacts_screen.dart b/lib/screens/contacts_screen.dart index 32799eb..3bae3dd 100644 --- a/lib/screens/contacts_screen.dart +++ b/lib/screens/contacts_screen.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../connector/meshcore_connector.dart'; +import '../l10n/l10n.dart'; import '../connector/meshcore_protocol.dart'; import '../models/contact.dart'; import '../models/contact_group.dart'; @@ -89,18 +90,18 @@ class _ContactsScreenState extends State child: Scaffold( appBar: AppBar( leading: BatteryIndicator(connector: connector), - title: const Text('Contacts'), + title: Text(context.l10n.contacts_title), centerTitle: true, automaticallyImplyLeading: false, actions: [ IconButton( icon: const Icon(Icons.bluetooth_disabled), - tooltip: 'Disconnect', + tooltip: context.l10n.common_disconnect, onPressed: () => _disconnect(context, connector), ), IconButton( icon: const Icon(Icons.tune), - tooltip: 'Settings', + tooltip: context.l10n.common_settings, onPressed: () => Navigator.push( context, MaterialPageRoute(builder: (context) => const SettingsScreen()), @@ -159,10 +160,10 @@ class _ContactsScreenState extends State } if (contacts.isEmpty && _groups.isEmpty) { - return const EmptyState( + return EmptyState( icon: Icons.people_outline, - title: 'No contacts yet', - subtitle: 'Contacts will appear when devices advertise', + title: context.l10n.contacts_noContacts, + subtitle: context.l10n.contacts_contactsWillAppear, ); } @@ -177,7 +178,7 @@ class _ContactsScreenState extends State child: TextField( controller: _searchController, decoration: InputDecoration( - hintText: 'Search contacts...', + hintText: context.l10n.contacts_searchContacts, prefixIcon: const Icon(Icons.search), suffixIcon: Row( mainAxisSize: MainAxisSize.min, @@ -221,8 +222,8 @@ class _ContactsScreenState extends State const SizedBox(height: 16), Text( _showUnreadOnly - ? 'No unread contacts' - : 'No contacts or groups found', + ? context.l10n.contacts_noUnreadContacts + : context.l10n.contacts_noContactsFound, style: TextStyle(fontSize: 16, color: Colors.grey[600]), ), ], @@ -341,7 +342,7 @@ class _ContactsScreenState extends State Widget _buildGroupTile(BuildContext context, ContactGroup group, List contacts) { final memberContacts = _resolveGroupContacts(group, contacts); - final subtitle = _formatGroupMembers(memberContacts); + final subtitle = _formatGroupMembers(context, memberContacts); return ListTile( leading: const CircleAvatar( backgroundColor: Colors.teal, @@ -374,8 +375,8 @@ class _ContactsScreenState extends State return resolved; } - String _formatGroupMembers(List members) { - if (members.isEmpty) return 'No members'; + String _formatGroupMembers(BuildContext context, List members) { + if (members.isEmpty) return context.l10n.contacts_noMembers; final names = members.map((c) => c.name).toList(); if (names.length <= 2) return names.join(', '); return '${names.take(2).join(', ')} +${names.length - 2}'; @@ -469,7 +470,7 @@ class _ContactsScreenState extends State children: [ ListTile( leading: const Icon(Icons.edit), - title: const Text('Edit Group'), + title: Text(context.l10n.contacts_editGroup), onTap: () { Navigator.pop(sheetContext); _showGroupEditor(context, contacts, group: group); @@ -477,7 +478,7 @@ class _ContactsScreenState extends State ), ListTile( leading: const Icon(Icons.delete, color: Colors.red), - title: const Text('Delete Group', style: TextStyle(color: Colors.red)), + title: Text(context.l10n.contacts_deleteGroup, style: const TextStyle(color: Colors.red)), onTap: () { Navigator.pop(sheetContext); _confirmDeleteGroup(context, group); @@ -506,12 +507,12 @@ class _ContactsScreenState extends State showDialog( context: context, builder: (dialogContext) => AlertDialog( - title: const Text('Delete Group'), - content: Text('Remove "${group.name}"?'), + title: Text(context.l10n.contacts_deleteGroup), + content: Text(context.l10n.contacts_deleteGroupConfirm(group.name)), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext), - child: const Text('Cancel'), + child: Text(context.l10n.common_cancel), ), TextButton( onPressed: () async { @@ -521,7 +522,7 @@ class _ContactsScreenState extends State }); await _saveGroups(); }, - child: const Text('Delete', style: TextStyle(color: Colors.red)), + child: Text(context.l10n.common_delete, style: const TextStyle(color: Colors.red)), ), ], ), @@ -550,7 +551,7 @@ class _ContactsScreenState extends State .where((contact) => matchesContactQuery(contact, filterQuery)) .toList(); return AlertDialog( - title: Text(isEditing ? 'Edit Group' : 'New Group'), + title: Text(isEditing ? context.l10n.contacts_editGroup : context.l10n.contacts_newGroup), content: SizedBox( width: double.maxFinite, child: Column( @@ -558,17 +559,17 @@ class _ContactsScreenState extends State children: [ TextField( controller: nameController, - decoration: const InputDecoration( - labelText: 'Group name', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: context.l10n.contacts_groupName, + border: const OutlineInputBorder(), ), ), const SizedBox(height: 12), TextField( - decoration: const InputDecoration( - hintText: 'Filter contacts...', - prefixIcon: Icon(Icons.search), - border: OutlineInputBorder(), + decoration: InputDecoration( + hintText: context.l10n.contacts_filterContacts, + prefixIcon: const Icon(Icons.search), + border: const OutlineInputBorder(), isDense: true, ), onChanged: (value) { @@ -581,7 +582,7 @@ class _ContactsScreenState extends State SizedBox( height: 240, child: filteredContacts.isEmpty - ? const Center(child: Text('No contacts match your filter')) + ? Center(child: Text(context.l10n.contacts_noContactsMatchFilter)) : ListView.builder( itemCount: filteredContacts.length, itemBuilder: (context, index) { @@ -610,14 +611,14 @@ class _ContactsScreenState extends State actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext), - child: const Text('Cancel'), + child: Text(context.l10n.common_cancel), ), TextButton( onPressed: () async { final name = nameController.text.trim(); if (name.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Group name is required')), + SnackBar(content: Text(context.l10n.contacts_groupNameRequired)), ); return; } @@ -627,7 +628,7 @@ class _ContactsScreenState extends State }); if (exists) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Group "$name" already exists')), + SnackBar(content: Text(context.l10n.contacts_groupAlreadyExists(name))), ); return; } @@ -649,7 +650,7 @@ class _ContactsScreenState extends State Navigator.pop(dialogContext); } }, - child: Text(isEditing ? 'Save' : 'Create'), + child: Text(isEditing ? context.l10n.common_save : context.l10n.common_create), ), ], ); @@ -668,42 +669,42 @@ class _ContactsScreenState extends State showModalBottomSheet( context: context, - builder: (context) => SafeArea( + builder: (sheetContext) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ if (isRepeater) ListTile( leading: const Icon(Icons.cell_tower, color: Colors.orange), - title: const Text('Manage Repeater'), + title: Text(context.l10n.contacts_manageRepeater), onTap: () { - Navigator.pop(context); + Navigator.pop(sheetContext); _showRepeaterLogin(context, contact); }, ) else if (isRoom) ListTile( leading: const Icon(Icons.room, color: Colors.blue), - title: const Text('Room Login'), + title: Text(context.l10n.contacts_roomLogin), onTap: () { - Navigator.pop(context); + Navigator.pop(sheetContext); _showRoomLogin(context, contact); }, ) else ListTile( leading: const Icon(Icons.chat), - title: const Text('Open Chat'), + title: Text(context.l10n.contacts_openChat), onTap: () { - Navigator.pop(context); + Navigator.pop(sheetContext); _openChat(context, contact); }, ), ListTile( leading: const Icon(Icons.delete, color: Colors.red), - title: const Text('Delete Contact', style: TextStyle(color: Colors.red)), + title: Text(context.l10n.contacts_deleteContact, style: const TextStyle(color: Colors.red)), onTap: () { - Navigator.pop(context); + Navigator.pop(sheetContext); _confirmDelete(context, connector, contact); }, ), @@ -720,20 +721,20 @@ class _ContactsScreenState extends State ) { showDialog( context: context, - builder: (context) => AlertDialog( - title: const Text('Delete Contact'), - content: Text('Remove ${contact.name} from contacts?'), + builder: (dialogContext) => AlertDialog( + title: Text(context.l10n.contacts_deleteContact), + content: Text(context.l10n.contacts_removeConfirm(contact.name)), actions: [ TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + onPressed: () => Navigator.pop(dialogContext), + child: Text(context.l10n.common_cancel), ), TextButton( onPressed: () { - Navigator.pop(context); + Navigator.pop(dialogContext); connector.removeContact(contact); }, - child: const Text('Delete', style: TextStyle(color: Colors.red)), + child: Text(context.l10n.common_delete, style: const TextStyle(color: Colors.red)), ), ], ), @@ -774,7 +775,7 @@ class _ContactTile extends StatelessWidget { const SizedBox(height: 4), ], Text( - _formatLastSeen(lastSeen), + _formatLastSeen(context, lastSeen), style: TextStyle(fontSize: 12, color: Colors.grey[600]), ), if (contact.hasLocation) @@ -827,17 +828,17 @@ class _ContactTile extends StatelessWidget { } } - String _formatLastSeen(DateTime lastSeen) { + String _formatLastSeen(BuildContext context, DateTime lastSeen) { final now = DateTime.now(); final diff = now.difference(lastSeen); - if (diff.isNegative || diff.inMinutes < 5) return 'Last seen now'; - if (diff.inMinutes < 60) return 'Last seen ${diff.inMinutes} mins ago'; + if (diff.isNegative || diff.inMinutes < 5) return context.l10n.contacts_lastSeenNow; + if (diff.inMinutes < 60) return context.l10n.contacts_lastSeenMinsAgo(diff.inMinutes); if (diff.inHours < 24) { final hours = diff.inHours; - return hours == 1 ? 'Last seen 1 hour ago' : 'Last seen $hours hours ago'; + return hours == 1 ? context.l10n.contacts_lastSeenHourAgo : context.l10n.contacts_lastSeenHoursAgo(hours); } final days = diff.inDays; - return days == 1 ? 'Last seen 1 day ago' : 'Last seen $days days ago'; + return days == 1 ? context.l10n.contacts_lastSeenDayAgo : context.l10n.contacts_lastSeenDaysAgo(days); } } diff --git a/lib/screens/device_screen.dart b/lib/screens/device_screen.dart index e288961..7a3b75b 100644 --- a/lib/screens/device_screen.dart +++ b/lib/screens/device_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../connector/meshcore_connector.dart'; +import '../l10n/l10n.dart'; import '../utils/dialog_utils.dart'; import '../utils/disconnect_navigation_mixin.dart'; import '../utils/route_transitions.dart'; @@ -47,12 +48,12 @@ class _DeviceScreenState extends State actions: [ IconButton( icon: const Icon(Icons.bluetooth_disabled), - tooltip: 'Disconnect', + tooltip: context.l10n.common_disconnect, onPressed: () => _disconnect(context, connector), ), IconButton( icon: const Icon(Icons.tune), - tooltip: 'Settings', + tooltip: context.l10n.common_settings, onPressed: () => Navigator.push( context, MaterialPageRoute( @@ -68,7 +69,7 @@ class _DeviceScreenState extends State children: [ _buildConnectionCard(connector, context), const SizedBox(height: 16), - _buildSectionLabel(theme, 'Quick switch'), + _buildSectionLabel(theme, context.l10n.device_quickSwitch), const SizedBox(height: 12), _buildQuickSwitchBar(context), ], @@ -87,7 +88,7 @@ class _DeviceScreenState extends State mainAxisSize: MainAxisSize.min, children: [ Text( - 'MeshCore', + context.l10n.device_meshcore, style: theme.textTheme.labelSmall?.copyWith( fontWeight: FontWeight.w600, letterSpacing: 0.8, @@ -180,7 +181,7 @@ class _DeviceScreenState extends State size: 18, color: colorScheme.onSecondaryContainer, ), - label: const Text('Connected'), + label: Text(context.l10n.common_connected), backgroundColor: colorScheme.secondaryContainer, labelStyle: theme.textTheme.labelMedium?.copyWith( color: colorScheme.onSecondaryContainer, diff --git a/lib/screens/map_cache_screen.dart b/lib/screens/map_cache_screen.dart index 248c035..3a1e1a9 100644 --- a/lib/screens/map_cache_screen.dart +++ b/lib/screens/map_cache_screen.dart @@ -3,6 +3,8 @@ import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; import 'package:provider/provider.dart'; +import '../l10n/app_localizations.dart'; +import '../l10n/l10n.dart'; import '../services/app_settings_service.dart'; import '../services/map_tile_cache_service.dart'; @@ -110,14 +112,14 @@ class _MapCacheScreenState extends State { final bounds = _selectedBounds; if (bounds == null) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Select an area to cache first')), + SnackBar(content: Text(context.l10n.mapCache_selectAreaFirst)), ); return; } if (_estimatedTiles == 0) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('No tiles to download for this area')), + SnackBar(content: Text(context.l10n.mapCache_noTilesToDownload)), ); return; } @@ -125,18 +127,18 @@ class _MapCacheScreenState extends State { final confirmed = await showDialog( context: context, builder: (dialogContext) => AlertDialog( - title: const Text('Download tiles'), + title: Text(context.l10n.mapCache_downloadTilesTitle), content: Text( - 'Download $_estimatedTiles tiles for offline use?', + context.l10n.mapCache_downloadTilesPrompt(_estimatedTiles), ), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext, false), - child: const Text('Cancel'), + child: Text(context.l10n.common_cancel), ), TextButton( onPressed: () => Navigator.pop(dialogContext, true), - child: const Text('Download'), + child: Text(context.l10n.mapCache_downloadAction), ), ], ), @@ -174,8 +176,11 @@ class _MapCacheScreenState extends State { }); final message = result.failed > 0 - ? 'Cached ${result.downloaded} tiles (${result.failed} failed)' - : 'Cached ${result.downloaded} tiles'; + ? context.l10n.mapCache_cachedTilesWithFailed( + result.downloaded, + result.failed, + ) + : context.l10n.mapCache_cachedTiles(result.downloaded); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(message)), ); @@ -185,16 +190,16 @@ class _MapCacheScreenState extends State { final confirmed = await showDialog( context: context, builder: (dialogContext) => AlertDialog( - title: const Text('Clear offline cache'), - content: const Text('Remove all cached map tiles?'), + title: Text(context.l10n.mapCache_clearOfflineCacheTitle), + content: Text(context.l10n.mapCache_clearOfflineCachePrompt), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext, false), - child: const Text('Cancel'), + child: Text(context.l10n.common_cancel), ), TextButton( onPressed: () => Navigator.pop(dialogContext, true), - child: const Text('Clear'), + child: Text(context.l10n.common_clear), ), ], ), @@ -205,7 +210,7 @@ class _MapCacheScreenState extends State { await cacheService.clearCache(); if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Offline cache cleared')), + SnackBar(content: Text(context.l10n.mapCache_offlineCacheCleared)), ); } @@ -213,13 +218,14 @@ class _MapCacheScreenState extends State { Widget build(BuildContext context) { final tileCache = context.read(); final selectedBounds = _selectedBounds; + final l10n = context.l10n; final progressValue = _estimatedTiles == 0 ? 0.0 : (_completedTiles / _estimatedTiles).clamp(0.0, 1.0).toDouble(); return Scaffold( appBar: AppBar( - title: const Text('Offline Map Cache'), + title: Text(l10n.mapCache_title), centerTitle: true, ), body: Column( @@ -264,8 +270,8 @@ class _MapCacheScreenState extends State { padding: const EdgeInsets.all(8), child: Text( selectedBounds == null - ? 'No area selected' - : _formatBounds(selectedBounds), + ? l10n.mapCache_noAreaSelected + : _formatBounds(selectedBounds, l10n), style: const TextStyle(fontSize: 12), ), ), @@ -282,9 +288,9 @@ class _MapCacheScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - const Text( - 'Cache Area', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + Text( + l10n.mapCache_cacheArea, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), ), const SizedBox(height: 8), Row( @@ -292,7 +298,7 @@ class _MapCacheScreenState extends State { Expanded( child: ElevatedButton.icon( icon: const Icon(Icons.crop_free), - label: const Text('Use Current View'), + label: Text(l10n.mapCache_useCurrentView), onPressed: _isDownloading ? null : _setBoundsFromView, ), ), @@ -300,14 +306,14 @@ class _MapCacheScreenState extends State { TextButton( onPressed: _isDownloading || selectedBounds == null ? null : _clearBounds, - child: const Text('Clear'), + child: Text(l10n.common_clear), ), ], ), const SizedBox(height: 12), - const Text( - 'Zoom Range', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + Text( + l10n.mapCache_zoomRange, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), ), RangeSlider( values: @@ -330,12 +336,15 @@ class _MapCacheScreenState extends State { _saveZoomRange(); }, ), - Text('Estimated tiles: $_estimatedTiles'), + Text(l10n.mapCache_estimatedTiles(_estimatedTiles)), if (_isDownloading) ...[ const SizedBox(height: 8), LinearProgressIndicator(value: progressValue), const SizedBox(height: 4), - Text('Downloaded $_completedTiles / $_estimatedTiles'), + Text(l10n.mapCache_downloadedTiles( + _completedTiles, + _estimatedTiles, + )), ], const SizedBox(height: 12), Row( @@ -343,7 +352,7 @@ class _MapCacheScreenState extends State { Expanded( child: ElevatedButton.icon( icon: const Icon(Icons.download), - label: const Text('Download Tiles'), + label: Text(l10n.mapCache_downloadTilesButton), onPressed: _isDownloading || selectedBounds == null ? null : _startDownload, @@ -352,7 +361,7 @@ class _MapCacheScreenState extends State { const SizedBox(width: 12), OutlinedButton( onPressed: _isDownloading ? null : _clearCache, - child: const Text('Clear Cache'), + child: Text(l10n.mapCache_clearCacheButton), ), ], ), @@ -360,7 +369,7 @@ class _MapCacheScreenState extends State { Padding( padding: const EdgeInsets.only(top: 8), child: Text( - 'Failed downloads: $_failedTiles', + l10n.mapCache_failedDownloads(_failedTiles), style: TextStyle(color: Colors.orange[700]), ), ), @@ -382,10 +391,12 @@ class _MapCacheScreenState extends State { ]; } - String _formatBounds(LatLngBounds bounds) { - return 'N ${bounds.north.toStringAsFixed(4)}, ' - 'S ${bounds.south.toStringAsFixed(4)}, ' - 'E ${bounds.east.toStringAsFixed(4)}, ' - 'W ${bounds.west.toStringAsFixed(4)}'; + String _formatBounds(LatLngBounds bounds, AppLocalizations l10n) { + return l10n.mapCache_boundsLabel( + bounds.north.toStringAsFixed(4), + bounds.south.toStringAsFixed(4), + bounds.east.toStringAsFixed(4), + bounds.west.toStringAsFixed(4), + ); } } diff --git a/lib/screens/map_screen.dart b/lib/screens/map_screen.dart index 4dc7971..bdc96c8 100644 --- a/lib/screens/map_screen.dart +++ b/lib/screens/map_screen.dart @@ -4,6 +4,7 @@ import 'package:latlong2/latlong.dart'; import 'package:provider/provider.dart'; import '../connector/meshcore_connector.dart'; +import '../l10n/l10n.dart'; import '../connector/meshcore_protocol.dart'; import '../models/channel.dart'; import '../models/contact.dart'; @@ -141,18 +142,18 @@ class _MapScreenState extends State { child: Scaffold( appBar: AppBar( leading: BatteryIndicator(connector: connector), - title: const Text('Node Map'), + title: Text(context.l10n.map_title), centerTitle: true, automaticallyImplyLeading: false, actions: [ IconButton( icon: const Icon(Icons.bluetooth_disabled), - tooltip: 'Disconnect', + tooltip: context.l10n.common_disconnect, onPressed: () => _disconnect(context, connector), ), IconButton( icon: const Icon(Icons.tune), - tooltip: 'Settings', + tooltip: context.l10n.common_settings, onPressed: () => Navigator.push( context, MaterialPageRoute(builder: (context) => const SettingsScreen()), @@ -180,7 +181,7 @@ class _MapScreenState extends State { context: context, connector: connector, position: latLng, - defaultLabel: 'Point of interest', + defaultLabel: context.l10n.map_pointOfInterest, flags: 'poi', ); } @@ -194,7 +195,7 @@ class _MapScreenState extends State { context: context, connector: connector, position: latLng, - defaultLabel: 'Point of interest', + defaultLabel: context.l10n.map_pointOfInterest, flags: 'poi', ); return; @@ -265,7 +266,7 @@ class _MapScreenState extends State { ), const SizedBox(height: 16), Text( - 'No nodes with location data', + context.l10n.map_noNodesWithLocation, style: TextStyle( fontSize: 18, color: Colors.grey[600], @@ -273,7 +274,7 @@ class _MapScreenState extends State { ), const SizedBox(height: 8), Text( - 'Nodes need to share their GPS coordinates\nto appear on the map', + context.l10n.map_nodesNeedGps, textAlign: TextAlign.center, style: TextStyle( fontSize: 14, @@ -381,27 +382,27 @@ class _MapScreenState extends State { mainAxisSize: MainAxisSize.min, children: [ Text( - 'Nodes: $nodeCount', + context.l10n.map_nodesCount(nodeCount), style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 14, ), ), Text( - 'Pins: $markerCount', + context.l10n.map_pinsCount(markerCount), style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 12, ), ), const SizedBox(height: 8), - _buildLegendItem(Icons.person, 'Chat', Colors.blue), - _buildLegendItem(Icons.router, 'Repeater', Colors.green), - _buildLegendItem(Icons.meeting_room, 'Room', Colors.purple), - _buildLegendItem(Icons.sensors, 'Sensor', Colors.orange), - _buildLegendItem(Icons.flag, 'Pin (DM)', Colors.blue), - _buildLegendItem(Icons.flag, 'Pin (Private)', Colors.purple), - _buildLegendItem(Icons.flag, 'Pin (Public)', Colors.orange), + _buildLegendItem(Icons.person, context.l10n.map_chat, Colors.blue), + _buildLegendItem(Icons.router, context.l10n.map_repeater, Colors.green), + _buildLegendItem(Icons.meeting_room, context.l10n.map_room, Colors.purple), + _buildLegendItem(Icons.sensors, context.l10n.map_sensor, Colors.orange), + _buildLegendItem(Icons.flag, context.l10n.map_pinDm, Colors.blue), + _buildLegendItem(Icons.flag, context.l10n.map_pinPrivate, Colors.purple), + _buildLegendItem(Icons.flag, context.l10n.map_pinPublic, Colors.orange), ], ), ), @@ -501,7 +502,7 @@ class _MapScreenState extends State { final flags = parts.length > 2 ? parts[2].trim() : ''; return _MarkerPayload( position: LatLng(lat, lon), - label: label.isEmpty ? 'Shared pin' : label, + label: label.isEmpty ? context.l10n.map_sharedPin : label, flags: flags, ); } @@ -595,7 +596,7 @@ class _MapScreenState extends State { void _showNodeInfo(BuildContext context, Contact contact) { showDialog( context: context, - builder: (context) => AlertDialog( + builder: (dialogContext) => AlertDialog( title: Row( children: [ Icon( @@ -614,19 +615,19 @@ class _MapScreenState extends State { _buildInfoRow('Path', contact.pathLabel), _buildInfoRow('Location', '${contact.latitude!.toStringAsFixed(6)}, ${contact.longitude!.toStringAsFixed(6)}'), - _buildInfoRow('Last Seen', _formatLastSeen(contact.lastSeen)), + _buildInfoRow(context.l10n.map_lastSeen, _formatLastSeen(contact.lastSeen)), _buildInfoRow('Public Key', contact.publicKeyHex), ], ), actions: [ TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Close'), + onPressed: () => Navigator.pop(dialogContext), + child: Text(context.l10n.common_close), ), if (contact.type == advTypeChat) // Only show chat button for chat nodes TextButton( onPressed: () { - Navigator.pop(context); + Navigator.pop(dialogContext); Navigator.push( context, MaterialPageRoute( @@ -634,23 +635,23 @@ class _MapScreenState extends State { ), ); }, - child: const Text('Open Chat'), + child: Text(context.l10n.contacts_openChat), ), if (contact.type == advTypeRepeater) TextButton( onPressed: () { - Navigator.pop(context); + Navigator.pop(dialogContext); _showRepeaterLogin(context, contact); }, - child: const Text('Manage Repeater'), + child: Text(context.l10n.map_manageRepeater), ), if (contact.type == advTypeRoom) TextButton( onPressed: () { - Navigator.pop(context); + Navigator.pop(dialogContext); _showRoomLogin(context, contact); }, - child: const Text('Join Room'), + child: Text(context.l10n.map_joinRoom), ), ], ), @@ -685,17 +686,17 @@ class _MapScreenState extends State { ) async { final confirmed = await showDialog( context: context, - builder: (context) => AlertDialog( - title: const Text('Disconnect'), - content: const Text('Are you sure you want to disconnect from this device?'), + builder: (dialogContext) => AlertDialog( + title: Text(context.l10n.common_disconnect), + content: Text(context.l10n.map_disconnectConfirm), actions: [ TextButton( - onPressed: () => Navigator.pop(context, false), - child: const Text('Cancel'), + onPressed: () => Navigator.pop(dialogContext, false), + child: Text(context.l10n.common_cancel), ), TextButton( - onPressed: () => Navigator.pop(context, true), - child: const Text('Disconnect'), + onPressed: () => Navigator.pop(dialogContext, true), + child: Text(context.l10n.common_disconnect), ), ], ), @@ -709,19 +710,19 @@ class _MapScreenState extends State { void _showMarkerInfo(_SharedMarker marker) { showDialog( context: context, - builder: (context) => AlertDialog( + builder: (dialogContext) => AlertDialog( title: Text(marker.label), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildInfoRow('From', marker.fromName), - _buildInfoRow('Source', marker.sourceLabel), + _buildInfoRow(context.l10n.map_from, marker.fromName), + _buildInfoRow(context.l10n.map_source, marker.sourceLabel), _buildInfoRow( 'Location', '${marker.position.latitude.toStringAsFixed(6)}, ${marker.position.longitude.toStringAsFixed(6)}', ), - if (marker.flags.isNotEmpty) _buildInfoRow('Flags', marker.flags), + if (marker.flags.isNotEmpty) _buildInfoRow(context.l10n.map_flags, marker.flags), ], ), actions: [ @@ -730,9 +731,9 @@ class _MapScreenState extends State { setState(() { _hiddenMarkerIds.add(marker.id); }); - Navigator.pop(context); + Navigator.pop(dialogContext); }, - child: const Text('Hide'), + child: Text(context.l10n.common_hide), ), TextButton( onPressed: () async { @@ -741,15 +742,15 @@ class _MapScreenState extends State { _removedMarkerIds.add(marker.id); }); await _markerService.saveRemovedIds(_removedMarkerIds); - if (context.mounted) { - Navigator.pop(context); + if (dialogContext.mounted) { + Navigator.pop(dialogContext); } }, - child: const Text('Remove'), + child: Text(context.l10n.common_remove), ), TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Close'), + onPressed: () => Navigator.pop(dialogContext), + child: Text(context.l10n.common_close), ), ], ), @@ -785,13 +786,13 @@ class _MapScreenState extends State { final difference = now.difference(lastSeen); if (difference.inSeconds < 60) { - return 'Just now'; + return context.l10n.time_justNow; } else if (difference.inMinutes < 60) { - return '${difference.inMinutes}m ago'; + return context.l10n.time_minutesAgo(difference.inMinutes); } else if (difference.inHours < 24) { - return '${difference.inHours}h ago'; + return context.l10n.time_hoursAgo(difference.inHours); } else { - return '${difference.inDays}d ago'; + return context.l10n.time_daysAgo(difference.inDays); } } @@ -808,21 +809,21 @@ class _MapScreenState extends State { children: [ ListTile( leading: const Icon(Icons.place), - title: const Text('Share marker here'), + title: Text(context.l10n.map_shareMarkerHere), onTap: () { Navigator.pop(sheetContext); _shareMarker( context: context, connector: connector, position: position, - defaultLabel: 'Point of interest', + defaultLabel: context.l10n.map_pointOfInterest, flags: 'poi', ); }, ), ListTile( leading: const Icon(Icons.close), - title: const Text('Cancel'), + title: Text(context.l10n.common_cancel), onTap: () => Navigator.pop(sheetContext), ), ], @@ -840,7 +841,7 @@ class _MapScreenState extends State { }) async { if (!connector.isConnected) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Connect to a device to share markers')), + SnackBar(content: Text(context.l10n.map_connectToShareMarkers)), ); return; } @@ -864,25 +865,25 @@ class _MapScreenState extends State { return showDialog( context: context, builder: (dialogContext) => AlertDialog( - title: const Text('Pin label'), + title: Text(context.l10n.map_pinLabel), content: TextField( controller: controller, - decoration: const InputDecoration( - hintText: 'Label', - border: OutlineInputBorder(), + decoration: InputDecoration( + hintText: context.l10n.map_label, + border: const OutlineInputBorder(), ), ), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext), - child: const Text('Cancel'), + child: Text(context.l10n.common_cancel), ), TextButton( onPressed: () { final label = controller.text.trim().replaceAll('|', '/'); Navigator.pop(dialogContext, label.isEmpty ? defaultLabel : label); }, - child: const Text('Continue'), + child: Text(context.l10n.common_continue), ), ], ), @@ -910,7 +911,7 @@ class _MapScreenState extends State { builder: (sheetContext) => StatefulBuilder( builder: (sheetContext, setSheetState) { return Consumer( - builder: (context, liveConnector, child) { + builder: (consumerContext, liveConnector, child) { final allContacts = liveConnector.contacts .where((contact) => contact.type != advTypeRepeater && contact.type != advTypeRoom) @@ -921,15 +922,15 @@ class _MapScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 12, 16, 4), - child: Text('Send to contact', style: TextStyle(fontWeight: FontWeight.bold)), + Padding( + padding: const EdgeInsets.fromLTRB(16, 12, 16, 4), + child: Text(context.l10n.map_sendToContact, style: const TextStyle(fontWeight: FontWeight.bold)), ), Padding( padding: const EdgeInsets.fromLTRB(16, 4, 16, 8), child: TextField( decoration: InputDecoration( - hintText: 'Search contacts...', + hintText: context.l10n.contacts_searchContacts, prefixIcon: const Icon(Icons.search), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), @@ -956,9 +957,9 @@ class _MapScreenState extends State { }, ); }), - const Padding( - padding: EdgeInsets.fromLTRB(16, 12, 16, 4), - child: Text('Send to channel', style: TextStyle(fontWeight: FontWeight.bold)), + Padding( + padding: const EdgeInsets.fromLTRB(16, 12, 16, 4), + child: Text(context.l10n.map_sendToChannel, style: const TextStyle(fontWeight: FontWeight.bold)), ), if (liveConnector.isLoadingChannels) const Padding( @@ -966,9 +967,9 @@ class _MapScreenState extends State { child: LinearProgressIndicator(), ) else if (liveConnector.channels.where((c) => !c.isEmpty).isEmpty) - const Padding( - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: Text('No channels available'), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Text(context.l10n.map_noChannelsAvailable), ) else ...liveConnector.channels.where((c) => !c.isEmpty).map((channel) { @@ -980,7 +981,7 @@ class _MapScreenState extends State { color: isPublic ? Colors.orange : Colors.blue, ), title: Text(label), - subtitle: isPublic ? const Text('Public channel') : null, + subtitle: isPublic ? Text(context.l10n.channels_publicChannel) : null, onTap: () async { Navigator.pop(sheetContext); final canSend = isPublic @@ -1011,19 +1012,16 @@ class _MapScreenState extends State { final result = await showDialog( context: context, builder: (dialogContext) => AlertDialog( - title: const Text('Public location share'), - content: Text( - 'You are about to share a location in $channelLabel. ' - 'This channel is public and anyone with the PSK can see it.', - ), + title: Text(context.l10n.map_publicLocationShare), + content: Text(context.l10n.map_publicLocationShareConfirm(channelLabel)), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext, false), - child: const Text('Cancel'), + child: Text(context.l10n.common_cancel), ), TextButton( onPressed: () => Navigator.pop(dialogContext, true), - child: const Text('Share'), + child: Text(context.l10n.common_share), ), ], ), @@ -1035,26 +1033,26 @@ class _MapScreenState extends State { showDialog( context: context, builder: (dialogContext) => AlertDialog( - title: const Text('Filter Nodes'), + title: Text(context.l10n.map_filterNodes), contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 0), content: SingleChildScrollView( child: Consumer( - builder: (context, service, child) { + builder: (consumerContext, service, child) { final settings = service.settings; return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'Node Types', - style: TextStyle( + Text( + context.l10n.map_nodeTypes, + style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), const SizedBox(height: 8), CheckboxListTile( - title: const Text('Chat Nodes'), + title: Text(context.l10n.map_chatNodes), value: settings.mapShowChatNodes, onChanged: (value) { service.setMapShowChatNodes(value ?? true); @@ -1062,7 +1060,7 @@ class _MapScreenState extends State { contentPadding: EdgeInsets.zero, ), CheckboxListTile( - title: const Text('Repeaters'), + title: Text(context.l10n.map_repeaters), value: settings.mapShowRepeaters, onChanged: (value) { service.setMapShowRepeaters(value ?? true); @@ -1070,7 +1068,7 @@ class _MapScreenState extends State { contentPadding: EdgeInsets.zero, ), CheckboxListTile( - title: const Text('Other Nodes'), + title: Text(context.l10n.map_otherNodes), value: settings.mapShowOtherNodes, onChanged: (value) { service.setMapShowOtherNodes(value ?? true); @@ -1078,16 +1076,16 @@ class _MapScreenState extends State { contentPadding: EdgeInsets.zero, ), const SizedBox(height: 16), - const Text( - 'Key Prefix', - style: TextStyle( + Text( + context.l10n.map_keyPrefix, + style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), const SizedBox(height: 8), CheckboxListTile( - title: const Text('Filter by key prefix'), + title: Text(context.l10n.map_filterByKeyPrefix), value: settings.mapKeyPrefixEnabled, onChanged: (value) { service.setMapKeyPrefixEnabled(value ?? false); @@ -1097,10 +1095,10 @@ class _MapScreenState extends State { TextFormField( initialValue: settings.mapKeyPrefix, enabled: settings.mapKeyPrefixEnabled, - decoration: const InputDecoration( - labelText: 'Public key prefix', + decoration: InputDecoration( + labelText: context.l10n.map_publicKeyPrefix, hintText: 'e.g. ab12', - border: OutlineInputBorder(), + border: const OutlineInputBorder(), isDense: true, ), onChanged: (value) { @@ -1108,16 +1106,16 @@ class _MapScreenState extends State { }, ), const SizedBox(height: 16), - const Text( - 'Markers', - style: TextStyle( + Text( + context.l10n.map_markers, + style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), const SizedBox(height: 8), CheckboxListTile( - title: const Text('Show shared markers'), + title: Text(context.l10n.map_showSharedMarkers), value: settings.mapShowMarkers, onChanged: (value) { service.setMapShowMarkers(value ?? true); @@ -1125,9 +1123,9 @@ class _MapScreenState extends State { contentPadding: EdgeInsets.zero, ), const SizedBox(height: 16), - const Text( - 'Last Seen Time', - style: TextStyle( + Text( + context.l10n.map_lastSeenTime, + style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), @@ -1158,7 +1156,7 @@ class _MapScreenState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext), - child: const Text('Close'), + child: Text(context.l10n.common_close), ), ], ), @@ -1205,23 +1203,24 @@ class _MapScreenState extends State { } String _getTimeFilterLabel(double hours) { - if (hours == 0) return 'All Time'; + if (hours == 0) return context.l10n.time_allTime; if (hours < 1) { - return '${(hours * 60).round()} minutes'; + return '${(hours * 60).round()} ${context.l10n.time_minutes}'; } else if (hours < 24) { - return '${hours.round()} ${hours.round() == 1 ? 'hour' : 'hours'}'; + final h = hours.round(); + return '$h ${h == 1 ? context.l10n.time_hour : context.l10n.time_hours}'; } else if (hours < 168) { final days = (hours / 24).round(); - return '$days ${days == 1 ? 'day' : 'days'}'; + return '$days ${days == 1 ? context.l10n.time_day : context.l10n.time_days}'; } else if (hours < 720) { final weeks = (hours / 168).round(); - return '$weeks ${weeks == 1 ? 'week' : 'weeks'}'; + return '$weeks ${weeks == 1 ? context.l10n.time_week : context.l10n.time_weeks}'; } else if (hours < 4380) { final months = (hours / 730).round(); - return '$months ${months == 1 ? 'month' : 'months'}'; + return '$months ${months == 1 ? context.l10n.time_month : context.l10n.time_months}'; } else { - return 'All Time'; + return context.l10n.time_allTime; } } } diff --git a/lib/screens/repeater_cli_screen.dart b/lib/screens/repeater_cli_screen.dart index 3487ebc..2a53a16 100644 --- a/lib/screens/repeater_cli_screen.dart +++ b/lib/screens/repeater_cli_screen.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import '../l10n/l10n.dart'; import '../models/contact.dart'; import '../connector/meshcore_connector.dart'; import '../connector/meshcore_protocol.dart'; @@ -33,14 +34,14 @@ class _RepeaterCliScreenState extends State { RepeaterCommandService? _commandService; // Common commands for quick access - final List> _quickCommands = [ - {'label': 'Get Name', 'command': 'get name'}, - {'label': 'Get Radio', 'command': 'get radio'}, - {'label': 'Get TX', 'command': 'get tx'}, - {'label': 'Neighbors', 'command': 'neighbors'}, - {'label': 'Version', 'command': 'ver'}, - {'label': 'Advertise', 'command': 'advert'}, - {'label': 'Clock', 'command': 'clock'}, + late final List> _quickCommands = [ + {'labelKey': 'getName', 'command': 'get name'}, + {'labelKey': 'getRadio', 'command': 'get radio'}, + {'labelKey': 'getTx', 'command': 'get tx'}, + {'labelKey': 'neighbors', 'command': 'neighbors'}, + {'labelKey': 'version', 'command': 'ver'}, + {'labelKey': 'advertise', 'command': 'advert'}, + {'labelKey': 'clock', 'command': 'clock'}, ]; @override @@ -119,7 +120,7 @@ class _RepeaterCliScreenState extends State { // Show debug info if requested if (showDebug && mounted) { final frame = buildSendCliCommandFrame(widget.repeater.publicKey, command); - DebugFrameViewer.showFrameDebug(context, frame, 'CLI Command Frame'); + DebugFrameViewer.showFrameDebug(context, frame, context.l10n.repeater_cliCommandFrameTitle); } // Send CLI command to repeater with retry @@ -148,7 +149,7 @@ class _RepeaterCliScreenState extends State { setState(() { _commandHistory.add({ 'type': 'response', - 'text': 'Error: $e', + 'text': context.l10n.repeater_cliCommandError(e.toString()), 'timestamp': DateTime.now().toString(), }); }); @@ -215,6 +216,7 @@ class _RepeaterCliScreenState extends State { @override Widget build(BuildContext context) { + final l10n = context.l10n; final connector = context.watch(); final repeater = _resolveRepeater(connector); final isFloodMode = repeater.pathOverride == -1; @@ -225,7 +227,7 @@ class _RepeaterCliScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - const Text('Repeater CLI'), + Text(l10n.repeater_cliTitle), Text( repeater.name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.normal), @@ -236,7 +238,7 @@ class _RepeaterCliScreenState extends State { actions: [ PopupMenuButton( icon: Icon(isFloodMode ? Icons.waves : Icons.route), - tooltip: 'Routing mode', + tooltip: l10n.repeater_routingMode, onSelected: (mode) async { if (mode == 'flood') { await connector.setPathOverride(repeater, pathLen: -1); @@ -252,7 +254,7 @@ class _RepeaterCliScreenState extends State { Icon(Icons.auto_mode, size: 20, color: !isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Auto (use saved path)', + l10n.repeater_autoUseSavedPath, style: TextStyle( fontWeight: !isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -267,7 +269,7 @@ class _RepeaterCliScreenState extends State { Icon(Icons.waves, size: 20, color: isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Force Flood Mode', + l10n.repeater_forceFloodMode, style: TextStyle( fontWeight: isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -279,31 +281,31 @@ class _RepeaterCliScreenState extends State { ), IconButton( icon: const Icon(Icons.timeline), - tooltip: 'Path management', + tooltip: l10n.repeater_pathManagement, onPressed: () => PathManagementDialog.show(context, contact: repeater), ), IconButton( icon: const Icon(Icons.bug_report), - tooltip: 'Debug Next Command', + tooltip: l10n.repeater_debugNextCommand, onPressed: () { // Set a flag or just send next command with debug if (_commandController.text.trim().isNotEmpty) { _sendCommand(showDebug: true); } else { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Enter a command first')), + SnackBar(content: Text(l10n.repeater_enterCommandFirst)), ); } }, ), IconButton( icon: const Icon(Icons.help_outline), - tooltip: 'Command Help', + tooltip: l10n.repeater_commandHelp, onPressed: () => _showCommandHelp(context), ), IconButton( icon: const Icon(Icons.clear_all), - tooltip: 'Clear History', + tooltip: l10n.repeater_clearHistory, onPressed: _commandHistory.isEmpty ? null : _clearHistory, ), ], @@ -331,10 +333,11 @@ class _RepeaterCliScreenState extends State { scrollDirection: Axis.horizontal, child: Row( children: _quickCommands.map((cmd) { + final label = _quickCommandLabel(cmd['labelKey']!); return Padding( padding: const EdgeInsets.only(right: 8), child: ActionChip( - label: Text(cmd['label']!), + label: Text(label), onPressed: () => _useQuickCommand(cmd['command']!), avatar: const Icon(Icons.play_arrow, size: 16), ), @@ -345,7 +348,30 @@ class _RepeaterCliScreenState extends State { ); } + String _quickCommandLabel(String key) { + final l10n = context.l10n; + switch (key) { + case 'getName': + return l10n.repeater_cliQuickGetName; + case 'getRadio': + return l10n.repeater_cliQuickGetRadio; + case 'getTx': + return l10n.repeater_cliQuickGetTx; + case 'neighbors': + return l10n.repeater_cliQuickNeighbors; + case 'version': + return l10n.repeater_cliQuickVersion; + case 'advertise': + return l10n.repeater_cliQuickAdvertise; + case 'clock': + return l10n.repeater_cliQuickClock; + default: + return key; + } + } + Widget _buildEmptyState() { + final l10n = context.l10n; return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -353,12 +379,12 @@ class _RepeaterCliScreenState extends State { Icon(Icons.terminal, size: 64, color: Colors.grey[400]), const SizedBox(height: 16), Text( - 'No commands sent yet', + l10n.repeater_noCommandsSent, style: TextStyle(fontSize: 16, color: Colors.grey[600]), ), const SizedBox(height: 8), Text( - 'Type a command below or use quick commands', + l10n.repeater_typeCommandOrUseQuick, style: TextStyle(fontSize: 14, color: Colors.grey[500]), ), ], @@ -422,6 +448,7 @@ class _RepeaterCliScreenState extends State { } Widget _buildCommandInput() { + final l10n = context.l10n; return Container( padding: const EdgeInsets.all(12), color: Theme.of(context).colorScheme.surface, @@ -430,12 +457,12 @@ class _RepeaterCliScreenState extends State { children: [ IconButton( icon: const Icon(Icons.arrow_upward, size: 20), - tooltip: 'Previous command', + tooltip: l10n.repeater_previousCommand, onPressed: () => _navigateHistory(true), ), IconButton( icon: const Icon(Icons.arrow_downward, size: 20), - tooltip: 'Next command', + tooltip: l10n.repeater_nextCommand, onPressed: () => _navigateHistory(false), ), const SizedBox(width: 8), @@ -443,10 +470,10 @@ class _RepeaterCliScreenState extends State { child: TextField( controller: _commandController, focusNode: _commandFocusNode, - decoration: const InputDecoration( - hintText: 'Enter command...', - border: OutlineInputBorder(), - contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: InputDecoration( + hintText: l10n.repeater_enterCommandHint, + border: const OutlineInputBorder(), + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), prefixText: '> ', ), style: const TextStyle(fontFamily: 'monospace'), @@ -479,312 +506,284 @@ class _RepeaterCliScreenState extends State { } void _showCommandHelp(BuildContext context) { + final l10n = context.l10n; final generalCommands = [ - const _CommandHelpEntry( + _CommandHelpEntry( command: 'advert', - description: 'Sends an advertisement packet', + description: l10n.repeater_cliHelpAdvert, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'reboot', - description: - "Reboots the device. (note, you'll prob get 'Timeout' which is normal)", + description: l10n.repeater_cliHelpReboot, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'clock', - description: "Displays current time per device's clock.", + description: l10n.repeater_cliHelpClock, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'password {new-password}', - description: 'Sets a new admin password for the device.', + description: l10n.repeater_cliHelpPassword, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'ver', - description: 'Shows the device version and firmware build date.', + description: l10n.repeater_cliHelpVersion, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'clear stats', - description: 'Resets various stats counters to zero.', + description: l10n.repeater_cliHelpClearStats, ), ]; final settingsCommands = [ - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set af {air-time-factor}', - description: 'Sets the air-time-factor.', + description: l10n.repeater_cliHelpSetAf, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set tx {tx-power-dbm}', - description: 'Sets LoRa transmit power in dBm. (reboot to apply)', + description: l10n.repeater_cliHelpSetTx, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set repeat {on|off}', - description: 'Enables or disables the repeater role for this node.', + description: l10n.repeater_cliHelpSetRepeat, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set allow.read.only {on|off}', - description: - "(Room server) If 'on', then login in blank password will be allowed, but cannot Post to room. (just read only)", + description: l10n.repeater_cliHelpSetAllowReadOnly, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set flood.max {max-hops}', - description: - 'Sets the maximum number of hops of inbound flood packet (if >= max, packet is not forwarded)', + description: l10n.repeater_cliHelpSetFloodMax, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set int.thresh {db}', - description: - 'Sets the Interference Threshold (in DB). Default is 14. Set to 0 to disable channel interference detection.', + description: l10n.repeater_cliHelpSetIntThresh, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set agc.reset.interval {seconds}', - description: - 'Sets the interval to reset the Auto Gain Controller. Set to 0 to disable.', + description: l10n.repeater_cliHelpSetAgcResetInterval, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set multi.acks {0|1}', - description: "Enables or disables the 'double ACKs' feature.", + description: l10n.repeater_cliHelpSetMultiAcks, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set advert.interval {minutes}', - description: - 'Sets the timer interval in minutes to send a local (zero-hop) advertisement packet. Set to 0 to disable.', + description: l10n.repeater_cliHelpSetAdvertInterval, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set flood.advert.interval {hours}', - description: - 'Sets the timer interval in hours to send a flood advertisement packet. Set to 0 to disable.', + description: l10n.repeater_cliHelpSetFloodAdvertInterval, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set guest.password {guess-password}', - description: - 'Sets/updates the guest password. (for repeaters, guest logins can send the "Get Stats" request)', + description: l10n.repeater_cliHelpSetGuestPassword, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set name {name}', - description: 'Sets the advertisement name.', + description: l10n.repeater_cliHelpSetName, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set lat {latitude}', - description: 'Sets the advertisement map latitude. (decimal degrees)', + description: l10n.repeater_cliHelpSetLat, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set lon {longitude}', - description: 'Sets the advertisement map longitude. (decimal degrees)', + description: l10n.repeater_cliHelpSetLon, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set radio {freq},{bw},{sf},{cr}', - description: - 'Sets completely new radio params, and saves to preferences. Requires a "reboot" command to apply.', + description: l10n.repeater_cliHelpSetRadio, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set rxdelay {base}', - description: - 'Sets (experimental) base (must be > 1 for effect) for applying slight delay to received packets, based on signal strength/score. Set to 0 to disable.', + description: l10n.repeater_cliHelpSetRxDelay, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set txdelay {factor}', - description: - 'Sets a factor multiplied with time-on-air for a flood-mode packet and with a randomized slot system, to delay its forwarding. (to decrease likelihood of collisions)', + description: l10n.repeater_cliHelpSetTxDelay, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set direct.txdelay {factor}', - description: - 'Same as txdelay, but for applying a random delay to the forwarding of direct-mode packets.', + description: l10n.repeater_cliHelpSetDirectTxDelay, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set bridge.enabled {on|off}', - description: 'Enable/Disable bridge.', + description: l10n.repeater_cliHelpSetBridgeEnabled, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set bridge.delay {0-10000}', - description: 'Set delay before retransmitting packets.', + description: l10n.repeater_cliHelpSetBridgeDelay, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set bridge.source {rx|tx}', - description: - 'Choose wether the bridge will retransmit received packets or transmitted packets.', + description: l10n.repeater_cliHelpSetBridgeSource, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set bridge.baud {speed}', - description: 'Set serial link baudrate for rs232 bridges.', + description: l10n.repeater_cliHelpSetBridgeBaud, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set bridge.secret {shared-secret}', - description: 'Set bridge secret for espnow bridges.', + description: l10n.repeater_cliHelpSetBridgeSecret, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'set adc.multiplier {factor}', - description: - 'Sets custom factor to adjust reported battery voltage (only supported on select boards).', + description: l10n.repeater_cliHelpSetAdcMultiplier, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'tempradio {freq},{bw},{sf},{cr},{minutes}', - description: - 'Sets temporary radio params for the given number of {minutes}, reverting to original radio params afterward. (does NOT save to preferences).', + description: l10n.repeater_cliHelpTempRadio, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'setperm {pubkey-hex} {permissions}', - description: - 'Modifies the ACL. Removes matching entry (by pubkey prefix) if "permissions" is zero. Adds new entry if pubkey-hex is full length and is not currently in ACL. Updates entry by matching pubkey prefix. Permission bits vary per firmware role, but low 2 bits are: 0 (Guest), 1 (Read only), 2 (Read write), 3 (Admin)', + description: l10n.repeater_cliHelpSetPerm, ), ]; final bridgeCommands = [ - const _CommandHelpEntry( + _CommandHelpEntry( command: 'get bridge.type', - description: 'Gets bridge type none, rs232, espnow', + description: l10n.repeater_cliHelpGetBridgeType, ), ]; final loggingCommands = [ - const _CommandHelpEntry( + _CommandHelpEntry( command: 'log start', - description: 'Starts packet logging to file system.', + description: l10n.repeater_cliHelpLogStart, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'log stop', - description: 'Stops packet logging to file system.', + description: l10n.repeater_cliHelpLogStop, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'log erase', - description: 'Erases the packet logs from file system.', + description: l10n.repeater_cliHelpLogErase, ), ]; final neighborCommands = [ - const _CommandHelpEntry( + _CommandHelpEntry( command: 'neighbors', - description: - 'Shows a list of other repeater nodes heard via zero-hop adverts. Each line is {id-prefix-hex}:{timestamp}:{snr-times-4}', + description: l10n.repeater_cliHelpNeighbors, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'neighbor.remove {pubkey-prefix}', - description: - 'Removes first matching entry (by pubkey prefix (hex)), from neighbors list.', + description: l10n.repeater_cliHelpNeighborRemove, ), ]; final regionCommands = [ - const _CommandHelpEntry( + _CommandHelpEntry( command: 'region', - description: - '(serial only) Lists all defined regions and current flood permissions.', + description: l10n.repeater_cliHelpRegion, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'region load', - description: - 'NOTE: this is a special multi-command invocation. Each subsequent command is a region name (indented with spaces to indicate parent hierarchy, with one space at minimum). Terminated by sending a blank line/command.', + description: l10n.repeater_cliHelpRegionLoad, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'region get {* | name-prefix}', - description: - 'Searches for region with given name prefix (or "*" for the global scope). Replies with "-> {region-name} ({parent-name}) {\'F\'}"', + description: l10n.repeater_cliHelpRegionGet, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'region put {name} {* | parent-name-prefix}', - description: 'Adds or updates a region definition with given name.', + description: l10n.repeater_cliHelpRegionPut, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'region remove {name}', - description: - 'Removes a region definition with given name. (must match exactly, and have no child regions)', + description: l10n.repeater_cliHelpRegionRemove, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'region allowf {* | name-prefix}', - description: - "Sets the 'F'lood permission for the given region. ('*' for the global/legacy scope)", + description: l10n.repeater_cliHelpRegionAllowf, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'region denyf {* | name-prefix}', - description: - "Removes the 'F'lood permission for the given region. (NOTE: at this stage NOT advised to use this on the global/legacy scope!!)", + description: l10n.repeater_cliHelpRegionDenyf, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'region home', - description: - "Replies with the current 'home' region. (Note applied anywhere yet, reserved for future)", + description: l10n.repeater_cliHelpRegionHome, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'region home {* | name-prefix}', - description: "Sets the 'home' region.", + description: l10n.repeater_cliHelpRegionHomeSet, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'region save', - description: 'Persists the region list/map to storage.', + description: l10n.repeater_cliHelpRegionSave, ), ]; final gpsCommands = [ - const _CommandHelpEntry( + _CommandHelpEntry( command: 'gps', - description: - 'Gives status of gps. When gps is off, it replies only off, if on it replies with on, {status}, {fix}, {sat count}', + description: l10n.repeater_cliHelpGps, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'gps {on|off}', - description: 'Toggles gps power state.', + description: l10n.repeater_cliHelpGpsOnOff, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'gps sync', - description: 'Syncs node time with gps clock.', + description: l10n.repeater_cliHelpGpsSync, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'gps setloc', - description: "Sets node's position to gps coordinates and save preferences.", + description: l10n.repeater_cliHelpGpsSetLoc, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'gps advert', - description: - "Gives location advert configuration of the node:\n- none: don't include location in adverts\n- share: share gps location (from SensorManager)\n- prefs: advert the location stored in preferences", + description: l10n.repeater_cliHelpGpsAdvert, ), - const _CommandHelpEntry( + _CommandHelpEntry( command: 'gps advert {none|share|prefs}', - description: 'Sets location advert configuration.', + description: l10n.repeater_cliHelpGpsAdvertSet, ), ]; showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Commands List'), + title: Text(l10n.repeater_commandsListTitle), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'NOTE: for the various "set ..." commands, there is also a "get ..." command.', - style: TextStyle(fontSize: 13), + Text( + l10n.repeater_commandsListNote, + style: const TextStyle(fontSize: 13), ), const SizedBox(height: 16), - _buildHelpSection(context, 'General', generalCommands), + _buildHelpSection(context, l10n.repeater_general, generalCommands), const SizedBox(height: 16), - _buildHelpSection(context, 'Settings', settingsCommands), + _buildHelpSection(context, l10n.repeater_settingsCategory, settingsCommands), const SizedBox(height: 16), - _buildHelpSection(context, 'Bridge', bridgeCommands), + _buildHelpSection(context, l10n.repeater_bridge, bridgeCommands), const SizedBox(height: 16), - _buildHelpSection(context, 'Logging', loggingCommands), + _buildHelpSection(context, l10n.repeater_logging, loggingCommands), const SizedBox(height: 16), _buildHelpSection( context, - 'Neighbors (Repeater only)', + l10n.repeater_neighborsRepeaterOnly, neighborCommands, ), const SizedBox(height: 16), _buildHelpSection( context, - 'Region Management (Repeater only)', + l10n.repeater_regionManagementRepeaterOnly, regionCommands, - note: - 'Region commands have been introduced to manage region definitions and permissions.', + note: l10n.repeater_regionNote, ), const SizedBox(height: 16), _buildHelpSection( context, - 'GPS Management', + l10n.repeater_gpsManagement, gpsCommands, - note: - 'gps command has been introduced to manage location related topics.', + note: l10n.repeater_gpsNote, ), ], ), @@ -792,7 +791,7 @@ class _RepeaterCliScreenState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Close'), + child: Text(l10n.common_close), ), ], ), diff --git a/lib/screens/repeater_hub_screen.dart b/lib/screens/repeater_hub_screen.dart index 8601daa..88a58fa 100644 --- a/lib/screens/repeater_hub_screen.dart +++ b/lib/screens/repeater_hub_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../l10n/l10n.dart'; import '../models/contact.dart'; import 'repeater_status_screen.dart'; import 'repeater_cli_screen.dart'; @@ -17,13 +18,14 @@ class RepeaterHubScreen extends StatelessWidget { @override Widget build(BuildContext context) { + final l10n = context.l10n; return Scaffold( appBar: AppBar( title: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - const Text('Repeater Management'), + Text(l10n.repeater_management), Text( repeater.name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.normal), @@ -77,17 +79,17 @@ class RepeaterHubScreen extends StatelessWidget { ), ), const SizedBox(height: 24), - const Text( - 'Management Tools', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + Text( + l10n.repeater_managementTools, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 16), // Status button _buildManagementCard( context, icon: Icons.analytics, - title: 'Status', - subtitle: 'View repeater status, stats, and neighbors', + title: l10n.repeater_status, + subtitle: l10n.repeater_statusSubtitle, color: Colors.blue, onTap: () { Navigator.push( @@ -102,12 +104,12 @@ class RepeaterHubScreen extends StatelessWidget { }, ), const SizedBox(height: 16), - // Status button + // Telemetry button _buildManagementCard( context, icon: Icons.bar_chart_sharp, - title: 'Telemetry', - subtitle: 'View telemetry of sensors and system stats', + title: l10n.repeater_telemetry, + subtitle: l10n.repeater_telemetrySubtitle, color: Colors.teal, onTap: () { Navigator.push( @@ -126,8 +128,8 @@ class RepeaterHubScreen extends StatelessWidget { _buildManagementCard( context, icon: Icons.terminal, - title: 'CLI', - subtitle: 'Send commands to the repeater', + title: l10n.repeater_cli, + subtitle: l10n.repeater_cliSubtitle, color: Colors.green, onTap: () { Navigator.push( @@ -146,8 +148,8 @@ class RepeaterHubScreen extends StatelessWidget { _buildManagementCard( context, icon: Icons.settings, - title: 'Settings', - subtitle: 'Configure repeater parameters', + title: l10n.repeater_settings, + subtitle: l10n.repeater_settingsSubtitle, color: Colors.orange, onTap: () { Navigator.push( diff --git a/lib/screens/repeater_settings_screen.dart b/lib/screens/repeater_settings_screen.dart index f39e355..02028ea 100644 --- a/lib/screens/repeater_settings_screen.dart +++ b/lib/screens/repeater_settings_screen.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import '../l10n/l10n.dart'; import '../models/contact.dart'; import '../connector/meshcore_connector.dart'; import '../connector/meshcore_protocol.dart'; @@ -32,7 +33,6 @@ class _RepeaterSettingsScreenState extends State { bool _refreshingLocation = false; bool _refreshingRepeat = false; bool _refreshingAllowReadOnly = false; - bool _refreshingPrivacy = false; bool _refreshingAdvertisement = false; StreamSubscription? _frameSubscription; RepeaterCommandService? _commandService; @@ -246,17 +246,6 @@ class _RepeaterSettingsScreenState extends State { }); } - bool _isAnySectionRefreshing() { - return _refreshingBasic || - _refreshingRadio || - _refreshingTxPower || - _refreshingLocation || - _refreshingRepeat || - _refreshingAllowReadOnly || - _refreshingPrivacy || - _refreshingAdvertisement; - } - bool _normalizeOnOff(String value) { final normalized = value.trim().toLowerCase(); return normalized == 'on' || @@ -398,6 +387,7 @@ class _RepeaterSettingsScreenState extends State { required ValueSetter setRefreshing, }) async { if (_commandService == null) return; + final l10n = context.l10n; setState(() { setRefreshing(true); @@ -426,14 +416,14 @@ class _RepeaterSettingsScreenState extends State { if (successCount > 0) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('$label refreshed'), + content: Text(l10n.repeater_refreshed(label)), backgroundColor: Colors.green, ), ); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Error refreshing $label'), + content: Text(l10n.repeater_errorRefreshing(label)), backgroundColor: Colors.red, ), ); @@ -449,64 +439,63 @@ class _RepeaterSettingsScreenState extends State { } Future _refreshBasicSettings() async { + final l10n = context.l10n; await _refreshSection( - label: 'Basic settings', + label: l10n.repeater_basicSettings, commands: const ['get name'], setRefreshing: (value) => _refreshingBasic = value, ); } Future _refreshRadioSettings() async { + final l10n = context.l10n; await _refreshSection( - label: 'Radio settings', + label: l10n.repeater_radioSettings, commands: const ['get radio'], setRefreshing: (value) => _refreshingRadio = value, ); } Future _refreshTxPower() async { + final l10n = context.l10n; await _refreshSection( - label: 'TX power', + label: l10n.repeater_txPower, commands: const ['get tx'], setRefreshing: (value) => _refreshingTxPower = value, ); } Future _refreshLocationSettings() async { + final l10n = context.l10n; await _refreshSection( - label: 'Location settings', + label: l10n.repeater_locationSettings, commands: const ['get lat', 'get lon'], setRefreshing: (value) => _refreshingLocation = value, ); } Future _refreshRepeat() async { + final l10n = context.l10n; await _refreshSection( - label: 'Packet forwarding', + label: l10n.repeater_packetForwarding, commands: const ['get repeat'], setRefreshing: (value) => _refreshingRepeat = value, ); } Future _refreshAllowReadOnly() async { + final l10n = context.l10n; await _refreshSection( - label: 'Guest access', + label: l10n.repeater_guestAccess, commands: const ['get allow.read.only'], setRefreshing: (value) => _refreshingAllowReadOnly = value, ); } - Future _refreshPrivacy() async { - await _refreshSection( - label: 'Privacy mode', - commands: const ['get privacy'], - setRefreshing: (value) => _refreshingPrivacy = value, - ); - } - Future _refreshAdvertisementSettings() async { + final l10n = context.l10n; await _refreshSection( - label: 'Advertisement settings', + label: l10n.repeater_advertisementSettings, commands: const [ 'get advert.interval', 'get flood.advert.interval', @@ -604,8 +593,8 @@ class _RepeaterSettingsScreenState extends State { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Settings saved successfully'), + SnackBar( + content: Text(context.l10n.repeater_settingsSaved), backgroundColor: Colors.green, ), ); @@ -618,7 +607,7 @@ class _RepeaterSettingsScreenState extends State { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Error saving settings: $e'), + content: Text(context.l10n.repeater_errorSavingSettings(e.toString())), backgroundColor: Colors.red, ), ); @@ -637,6 +626,7 @@ class _RepeaterSettingsScreenState extends State { Widget _buildSectionHeader({ required IconData icon, required String title, + required String tooltip, required bool isRefreshing, required VoidCallback onRefresh, }) { @@ -658,7 +648,7 @@ class _RepeaterSettingsScreenState extends State { ) : const Icon(Icons.refresh), onPressed: isRefreshing ? null : onRefresh, - tooltip: 'Refresh $title', + tooltip: tooltip, ), ], ); @@ -688,6 +678,7 @@ class _RepeaterSettingsScreenState extends State { @override Widget build(BuildContext context) { + final l10n = context.l10n; final connector = context.watch(); final repeater = _resolveRepeater(connector); final isFloodMode = repeater.pathOverride == -1; @@ -698,7 +689,7 @@ class _RepeaterSettingsScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - const Text('Repeater Settings'), + Text(l10n.repeater_settingsTitle), Text( repeater.name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.normal), @@ -709,7 +700,7 @@ class _RepeaterSettingsScreenState extends State { actions: [ PopupMenuButton( icon: Icon(isFloodMode ? Icons.waves : Icons.route), - tooltip: 'Routing mode', + tooltip: l10n.repeater_routingMode, onSelected: (mode) async { if (mode == 'flood') { await connector.setPathOverride(repeater, pathLen: -1); @@ -728,7 +719,7 @@ class _RepeaterSettingsScreenState extends State { Icon(Icons.auto_mode, size: 20, color: !isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Auto (use saved path)', + l10n.repeater_autoUseSavedPath, style: TextStyle( fontWeight: !isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -743,7 +734,7 @@ class _RepeaterSettingsScreenState extends State { Icon(Icons.waves, size: 20, color: isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Force Flood Mode', + l10n.repeater_forceFloodMode, style: TextStyle( fontWeight: isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -755,14 +746,14 @@ class _RepeaterSettingsScreenState extends State { ), IconButton( icon: const Icon(Icons.timeline), - tooltip: 'Path management', + tooltip: l10n.repeater_pathManagement, onPressed: () => PathManagementDialog.show(context, contact: repeater), ), if (_hasChanges) TextButton.icon( onPressed: _isLoading ? null : _saveSettings, icon: const Icon(Icons.save), - label: const Text('Save'), + label: Text(l10n.common_save), ), ], ), @@ -791,6 +782,7 @@ class _RepeaterSettingsScreenState extends State { } Widget _buildBasicSettingsCard() { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(16), @@ -799,27 +791,28 @@ class _RepeaterSettingsScreenState extends State { children: [ _buildSectionHeader( icon: Icons.settings, - title: 'Basic Settings', + title: l10n.repeater_basicSettings, + tooltip: l10n.repeater_refreshBasicSettings, isRefreshing: _refreshingBasic, onRefresh: _refreshBasicSettings, ), const Divider(), TextField( controller: _nameController, - decoration: const InputDecoration( - labelText: 'Repeater Name', - helperText: 'Display name for this repeater', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.repeater_repeaterName, + helperText: l10n.repeater_repeaterNameHelper, + border: const OutlineInputBorder(), ), onChanged: (_) => _markChanged(), ), const SizedBox(height: 16), TextField( controller: _passwordController, - decoration: const InputDecoration( - labelText: 'Admin Password', - helperText: 'Full access password', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.repeater_adminPassword, + helperText: l10n.repeater_adminPasswordHelper, + border: const OutlineInputBorder(), ), obscureText: true, onChanged: (_) => _markChanged(), @@ -827,10 +820,10 @@ class _RepeaterSettingsScreenState extends State { const SizedBox(height: 16), TextField( controller: _guestPasswordController, - decoration: const InputDecoration( - labelText: 'Guest Password', - helperText: 'Read-only access password', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.repeater_guestPassword, + helperText: l10n.repeater_guestPasswordHelper, + border: const OutlineInputBorder(), ), obscureText: true, onChanged: (_) => _markChanged(), @@ -842,6 +835,7 @@ class _RepeaterSettingsScreenState extends State { } Widget _buildRadioSettingsCard() { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(16), @@ -850,17 +844,18 @@ class _RepeaterSettingsScreenState extends State { children: [ _buildSectionHeader( icon: Icons.radio, - title: 'Radio Settings', + title: l10n.repeater_radioSettings, + tooltip: l10n.repeater_refreshRadioSettings, isRefreshing: _refreshingRadio, onRefresh: _refreshRadioSettings, ), const Divider(), TextField( controller: _freqController, - decoration: const InputDecoration( - labelText: 'Frequency (MHz)', - helperText: '300-2500 MHz', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.repeater_frequencyMhz, + helperText: l10n.repeater_frequencyHelper, + border: const OutlineInputBorder(), suffixText: 'MHz', ), keyboardType: const TextInputType.numberWithOptions(decimal: true), @@ -873,10 +868,10 @@ class _RepeaterSettingsScreenState extends State { Expanded( child: TextField( controller: _txPowerController, - decoration: const InputDecoration( - labelText: 'TX Power', - helperText: '1-30 dBm', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.repeater_txPower, + helperText: l10n.repeater_txPowerHelper, + border: const OutlineInputBorder(), suffixText: 'dBm', ), keyboardType: TextInputType.number, @@ -887,16 +882,16 @@ class _RepeaterSettingsScreenState extends State { _buildInlineRefreshButton( isRefreshing: _refreshingTxPower, onRefresh: _refreshTxPower, - tooltip: 'Refresh TX power', + tooltip: l10n.repeater_refreshTxPower, ), ], ), const SizedBox(height: 16), DropdownButtonFormField( initialValue: _bandwidth, - decoration: const InputDecoration( - labelText: 'Bandwidth', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.repeater_bandwidth, + border: const OutlineInputBorder(), ), items: _bandwidthOptions.map((bw) { return DropdownMenuItem( @@ -916,9 +911,9 @@ class _RepeaterSettingsScreenState extends State { const SizedBox(height: 16), DropdownButtonFormField( initialValue: _spreadingFactor, - decoration: const InputDecoration( - labelText: 'Spreading Factor', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.repeater_spreadingFactor, + border: const OutlineInputBorder(), ), items: _spreadingFactorOptions.map((sf) { return DropdownMenuItem( @@ -938,9 +933,9 @@ class _RepeaterSettingsScreenState extends State { const SizedBox(height: 16), DropdownButtonFormField( initialValue: _codingRate, - decoration: const InputDecoration( - labelText: 'Coding Rate', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.repeater_codingRate, + border: const OutlineInputBorder(), ), items: _codingRateOptions.map((cr) { return DropdownMenuItem( @@ -964,6 +959,7 @@ class _RepeaterSettingsScreenState extends State { } Widget _buildLocationSettingsCard() { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(16), @@ -972,17 +968,18 @@ class _RepeaterSettingsScreenState extends State { children: [ _buildSectionHeader( icon: Icons.location_on, - title: 'Location Settings', + title: l10n.repeater_locationSettings, + tooltip: l10n.repeater_refreshLocationSettings, isRefreshing: _refreshingLocation, onRefresh: _refreshLocationSettings, ), const Divider(), TextField( controller: _latController, - decoration: const InputDecoration( - labelText: 'Latitude', - helperText: 'Decimal degrees (e.g., 37.7749)', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.repeater_latitude, + helperText: l10n.repeater_latitudeHelper, + border: const OutlineInputBorder(), ), keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true), onChanged: (_) => _markChanged(), @@ -990,10 +987,10 @@ class _RepeaterSettingsScreenState extends State { const SizedBox(height: 16), TextField( controller: _lonController, - decoration: const InputDecoration( - labelText: 'Longitude', - helperText: 'Decimal degrees (e.g., -122.4194)', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.repeater_longitude, + helperText: l10n.repeater_longitudeHelper, + border: const OutlineInputBorder(), ), keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true), onChanged: (_) => _markChanged(), @@ -1005,6 +1002,7 @@ class _RepeaterSettingsScreenState extends State { } Widget _buildFeatureTogglesCard() { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(16), @@ -1015,16 +1013,16 @@ class _RepeaterSettingsScreenState extends State { children: [ Icon(Icons.toggle_on, color: Theme.of(context).textTheme.headlineSmall?.color), const SizedBox(width: 8), - const Text( - 'Features', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + Text( + l10n.repeater_features, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ], ), const Divider(), _buildFeatureToggleRow( - title: 'Packet Forwarding', - subtitle: 'Enable repeater to forward packets', + title: l10n.repeater_packetForwarding, + subtitle: l10n.repeater_packetForwardingSubtitle, value: _repeatEnabled, isRefreshing: _refreshingRepeat, onChanged: (value) { @@ -1034,10 +1032,11 @@ class _RepeaterSettingsScreenState extends State { _markChanged(); }, onRefresh: _refreshRepeat, + refreshTooltip: l10n.repeater_refreshPacketForwarding, ), _buildFeatureToggleRow( - title: 'Guest Access', - subtitle: 'Allow read-only guest access', + title: l10n.repeater_guestAccess, + subtitle: l10n.repeater_guestAccessSubtitle, value: _allowReadOnly, isRefreshing: _refreshingAllowReadOnly, onChanged: (value) { @@ -1047,11 +1046,12 @@ class _RepeaterSettingsScreenState extends State { _markChanged(); }, onRefresh: _refreshAllowReadOnly, + refreshTooltip: l10n.repeater_refreshGuestAccess, ), // Privacy mode - hidden until fully implemented // _buildFeatureToggleRow( - // title: 'Privacy Mode', - // subtitle: 'Hide name/location in advertisements', + // title: l10n.repeater_privacyMode, + // subtitle: l10n.repeater_privacyModeSubtitle, // value: _privacyMode, // isRefreshing: _refreshingPrivacy, // onChanged: (value) { @@ -1061,6 +1061,7 @@ class _RepeaterSettingsScreenState extends State { // _markChanged(); // }, // onRefresh: _refreshPrivacy, + // refreshTooltip: l10n.repeater_refreshPrivacyMode, // ), ], ), @@ -1075,6 +1076,7 @@ class _RepeaterSettingsScreenState extends State { required bool isRefreshing, required ValueChanged onChanged, required VoidCallback onRefresh, + required String refreshTooltip, }) { return Row( children: [ @@ -1093,10 +1095,10 @@ class _RepeaterSettingsScreenState extends State { width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2), - ) + ) : const Icon(Icons.refresh, size: 20), onPressed: isRefreshing ? null : onRefresh, - tooltip: 'Refresh $title', + tooltip: refreshTooltip, visualDensity: VisualDensity.compact, ), ], @@ -1104,6 +1106,7 @@ class _RepeaterSettingsScreenState extends State { } Widget _buildAdvertisementSettingsCard() { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(16), @@ -1112,22 +1115,23 @@ class _RepeaterSettingsScreenState extends State { children: [ _buildSectionHeader( icon: Icons.broadcast_on_personal, - title: 'Advertisement Settings', + title: l10n.repeater_advertisementSettings, + tooltip: l10n.repeater_refreshAdvertisementSettings, isRefreshing: _refreshingAdvertisement, onRefresh: _refreshAdvertisementSettings, ), const Divider(), ListTile( - title: const Text('Local Advertisement Interval'), - subtitle: Text('$_advertInterval minutes'), - trailing: Text('${_advertInterval}m'), + title: Text(l10n.repeater_localAdvertInterval), + subtitle: Text(l10n.repeater_localAdvertIntervalMinutes(_advertInterval)), + trailing: Text(l10n.repeater_localAdvertIntervalMinutes(_advertInterval)), ), Slider( value: _advertInterval.toDouble(), min: 60, max: 240, divisions: 18, - label: '${_advertInterval}m', + label: l10n.repeater_localAdvertIntervalMinutes(_advertInterval), onChanged: (value) { setState(() { _advertInterval = value.toInt(); @@ -1137,16 +1141,16 @@ class _RepeaterSettingsScreenState extends State { ), const SizedBox(height: 16), ListTile( - title: const Text('Flood Advertisement Interval'), - subtitle: Text('$_floodAdvertInterval hours'), - trailing: Text('${_floodAdvertInterval}h'), + title: Text(l10n.repeater_floodAdvertInterval), + subtitle: Text(l10n.repeater_floodAdvertIntervalHours(_floodAdvertInterval)), + trailing: Text(l10n.repeater_floodAdvertIntervalHours(_floodAdvertInterval)), ), Slider( value: _floodAdvertInterval.toDouble(), min: 3, max: 48, divisions: 45, - label: '${_floodAdvertInterval}h', + label: l10n.repeater_floodAdvertIntervalHours(_floodAdvertInterval), onChanged: (value) { setState(() { _floodAdvertInterval = value.toInt(); @@ -1158,16 +1162,16 @@ class _RepeaterSettingsScreenState extends State { // if (_privacyMode) ...[ // const SizedBox(height: 16), // ListTile( - // title: const Text('Encrypted Advertisement Interval'), - // subtitle: Text('$_privAdvertInterval minutes'), - // trailing: Text('${_privAdvertInterval}m'), + // title: Text(l10n.repeater_encryptedAdvertInterval), + // subtitle: Text(l10n.repeater_localAdvertIntervalMinutes(_privAdvertInterval)), + // trailing: Text(l10n.repeater_localAdvertIntervalMinutes(_privAdvertInterval)), // ), // Slider( // value: _privAdvertInterval.toDouble(), // min: 30, // max: 240, // divisions: 21, - // label: '${_privAdvertInterval}m', + // label: l10n.repeater_localAdvertIntervalMinutes(_privAdvertInterval), // onChanged: (value) { // setState(() { // _privAdvertInterval = value.toInt(); @@ -1183,6 +1187,7 @@ class _RepeaterSettingsScreenState extends State { } Widget _buildDangerZoneCard() { + final l10n = context.l10n; final colorScheme = Theme.of(context).colorScheme; return Card( color: colorScheme.errorContainer, @@ -1196,7 +1201,7 @@ class _RepeaterSettingsScreenState extends State { Icon(Icons.warning, color: colorScheme.onErrorContainer), const SizedBox(width: 8), Text( - 'Danger Zone', + l10n.repeater_dangerZone, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, @@ -1208,14 +1213,14 @@ class _RepeaterSettingsScreenState extends State { const Divider(), ListTile( leading: Icon(Icons.refresh, color: colorScheme.onErrorContainer), - title: Text('Reboot Repeater', style: TextStyle(color: colorScheme.onErrorContainer)), + title: Text(l10n.repeater_rebootRepeater, style: TextStyle(color: colorScheme.onErrorContainer)), subtitle: Text( - 'Restart the repeater device', + l10n.repeater_rebootRepeaterSubtitle, style: TextStyle(color: colorScheme.onErrorContainer.withValues(alpha: 0.8)), ), onTap: () => _confirmAction( - 'Reboot Repeater', - 'Are you sure you want to reboot this repeater?', + l10n.repeater_rebootRepeater, + l10n.repeater_rebootRepeaterConfirm, () => _sendDangerCommand('reboot'), ), ), @@ -1235,14 +1240,14 @@ class _RepeaterSettingsScreenState extends State { // ), ListTile( leading: Icon(Icons.delete_forever, color: colorScheme.onErrorContainer), - title: Text('Erase File System', style: TextStyle(color: colorScheme.onErrorContainer)), + title: Text(l10n.repeater_eraseFileSystem, style: TextStyle(color: colorScheme.onErrorContainer)), subtitle: Text( - 'Format the repeater file system', + l10n.repeater_eraseFileSystemSubtitle, style: TextStyle(color: colorScheme.onErrorContainer.withValues(alpha: 0.8)), ), onTap: () => _confirmAction( - 'Erase File System', - 'WARNING: This will erase all data on the repeater. This cannot be undone!', + l10n.repeater_eraseFileSystem, + l10n.repeater_eraseFileSystemConfirm, () => _sendDangerCommand('erase'), isDestructive: true, ), @@ -1254,13 +1259,14 @@ class _RepeaterSettingsScreenState extends State { } Future _sendDangerCommand(String command) async { + final l10n = context.l10n; final connector = Provider.of(context, listen: false); final repeater = _resolveRepeater(connector); if (command == 'erase') { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Erase is only available over serial console.')), + SnackBar(content: Text(l10n.repeater_eraseSerialOnly)), ); } return; @@ -1284,14 +1290,14 @@ class _RepeaterSettingsScreenState extends State { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Command sent: $command')), + SnackBar(content: Text(l10n.repeater_commandSent(command))), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Error sending command: $e'), + content: Text(l10n.repeater_errorSendingCommand(e.toString())), backgroundColor: Colors.red, ), ); @@ -1305,6 +1311,7 @@ class _RepeaterSettingsScreenState extends State { VoidCallback onConfirm, { bool isDestructive = false, }) { + final l10n = context.l10n; showDialog( context: context, builder: (context) => AlertDialog( @@ -1313,7 +1320,7 @@ class _RepeaterSettingsScreenState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + child: Text(l10n.common_cancel), ), FilledButton( onPressed: () { @@ -1323,7 +1330,7 @@ class _RepeaterSettingsScreenState extends State { style: isDestructive ? FilledButton.styleFrom(backgroundColor: Colors.red) : null, - child: const Text('Confirm'), + child: Text(l10n.repeater_confirm), ), ], ), diff --git a/lib/screens/repeater_status_screen.dart b/lib/screens/repeater_status_screen.dart index ddb1784..5a3fa75 100644 --- a/lib/screens/repeater_status_screen.dart +++ b/lib/screens/repeater_status_screen.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import '../l10n/l10n.dart'; import '../models/contact.dart'; import '../models/path_selection.dart'; import '../connector/meshcore_connector.dart'; @@ -274,8 +275,8 @@ class _RepeaterStatusScreenState extends State { _isLoading = false; }); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Status request timed out.'), + SnackBar( + content: Text(context.l10n.repeater_statusRequestTimeout), backgroundColor: Colors.red, ), ); @@ -289,7 +290,7 @@ class _RepeaterStatusScreenState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Error loading status: $e'), + content: Text(context.l10n.repeater_errorLoadingStatus(e.toString())), backgroundColor: Colors.red, ), ); @@ -309,6 +310,7 @@ class _RepeaterStatusScreenState extends State { @override Widget build(BuildContext context) { + final l10n = context.l10n; final connector = context.watch(); final repeater = _resolveRepeater(connector); final isFloodMode = repeater.pathOverride == -1; @@ -319,7 +321,7 @@ class _RepeaterStatusScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - const Text('Repeater Status'), + Text(l10n.repeater_statusTitle), Text( repeater.name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.normal), @@ -330,7 +332,7 @@ class _RepeaterStatusScreenState extends State { actions: [ PopupMenuButton( icon: Icon(isFloodMode ? Icons.waves : Icons.route), - tooltip: 'Routing mode', + tooltip: l10n.repeater_routingMode, onSelected: (mode) async { if (mode == 'flood') { await connector.setPathOverride(repeater, pathLen: -1); @@ -346,7 +348,7 @@ class _RepeaterStatusScreenState extends State { Icon(Icons.auto_mode, size: 20, color: !isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Auto (use saved path)', + l10n.repeater_autoUseSavedPath, style: TextStyle( fontWeight: !isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -361,7 +363,7 @@ class _RepeaterStatusScreenState extends State { Icon(Icons.waves, size: 20, color: isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Force Flood Mode', + l10n.repeater_forceFloodMode, style: TextStyle( fontWeight: isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -373,7 +375,7 @@ class _RepeaterStatusScreenState extends State { ), IconButton( icon: const Icon(Icons.timeline), - tooltip: 'Path management', + tooltip: l10n.repeater_pathManagement, onPressed: () => PathManagementDialog.show(context, contact: repeater), ), IconButton( @@ -385,7 +387,7 @@ class _RepeaterStatusScreenState extends State { ) : const Icon(Icons.refresh), onPressed: _isLoading ? null : _loadStatus, - tooltip: 'Refresh', + tooltip: l10n.repeater_refresh, ), ], ), @@ -409,6 +411,7 @@ class _RepeaterStatusScreenState extends State { } Widget _buildSystemInfoCard() { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(16), @@ -419,18 +422,18 @@ class _RepeaterStatusScreenState extends State { children: [ Icon(Icons.info_outline, color: Theme.of(context).textTheme.headlineSmall?.color), const SizedBox(width: 8), - const Text( - 'System Information', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + Text( + l10n.repeater_systemInformation, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ], ), const Divider(), - _buildInfoRow('Battery', _batteryText()), - _buildInfoRow('Clock (at login)', _clockText()), - _buildInfoRow('Uptime', _formatDuration(_uptimeSecs)), - _buildInfoRow('Queue Length', _formatValue(_queueLen)), - _buildInfoRow('Debug Flags', _formatValue(_debugFlags)), + _buildInfoRow(l10n.repeater_battery, _batteryText()), + _buildInfoRow(l10n.repeater_clockAtLogin, _clockText()), + _buildInfoRow(l10n.repeater_uptime, _formatDuration(_uptimeSecs)), + _buildInfoRow(l10n.repeater_queueLength, _formatValue(_queueLen)), + _buildInfoRow(l10n.repeater_debugFlags, _formatValue(_debugFlags)), ], ), ), @@ -438,6 +441,7 @@ class _RepeaterStatusScreenState extends State { } Widget _buildRadioStatsCard() { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(16), @@ -448,18 +452,18 @@ class _RepeaterStatusScreenState extends State { children: [ Icon(Icons.radio, color: Theme.of(context).textTheme.headlineSmall?.color), const SizedBox(width: 8), - const Text( - 'Radio Statistics', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + Text( + l10n.repeater_radioStatistics, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ], ), const Divider(), - _buildInfoRow('Last RSSI', _formatValue(_lastRssi, suffix: ' dB')), - _buildInfoRow('Last SNR', _formatSnr(_lastSnr)), - _buildInfoRow('Noise Floor', _formatValue(_noiseFloor, suffix: ' dB')), - _buildInfoRow('TX Airtime', _formatDuration(_txAirSecs)), - _buildInfoRow('RX Airtime', _formatDuration(_rxAirSecs)), + _buildInfoRow(l10n.repeater_lastRssi, _formatValue(_lastRssi, suffix: ' dB')), + _buildInfoRow(l10n.repeater_lastSnr, _formatSnr(_lastSnr)), + _buildInfoRow(l10n.repeater_noiseFloor, _formatValue(_noiseFloor, suffix: ' dB')), + _buildInfoRow(l10n.repeater_txAirtime, _formatDuration(_txAirSecs)), + _buildInfoRow(l10n.repeater_rxAirtime, _formatDuration(_rxAirSecs)), ], ), ), @@ -467,6 +471,7 @@ class _RepeaterStatusScreenState extends State { } Widget _buildPacketStatsCard() { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(16), @@ -477,16 +482,16 @@ class _RepeaterStatusScreenState extends State { children: [ Icon(Icons.analytics, color: Theme.of(context).textTheme.headlineSmall?.color), const SizedBox(width: 8), - const Text( - 'Packet Statistics', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + Text( + l10n.repeater_packetStatistics, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ], ), const Divider(), - _buildInfoRow('Sent', _packetTxText()), - _buildInfoRow('Received', _packetRxText()), - _buildInfoRow('Duplicates', _duplicateText()), + _buildInfoRow(l10n.repeater_sent, _packetTxText()), + _buildInfoRow(l10n.repeater_received, _packetRxText()), + _buildInfoRow(l10n.repeater_duplicates, _duplicateText()), ], ), ), @@ -559,37 +564,41 @@ class _RepeaterStatusScreenState extends State { String _formatDuration(int? seconds) { if (seconds == null) return '—'; + final l10n = context.l10n; final days = seconds ~/ 86400; final hours = (seconds % 86400) ~/ 3600; final minutes = (seconds % 3600) ~/ 60; final secs = seconds % 60; - return '$days days ${hours}h ${minutes}m ${secs}s'; + return l10n.repeater_daysHoursMinsSecs(days, hours, minutes, secs); } String _packetTxText() { if (_packetsSent == null) return '—'; + final l10n = context.l10n; final flood = _formatValue(_floodTx); final direct = _formatValue(_directTx); - return 'Total: $_packetsSent, Flood: $flood, Direct: $direct'; + return l10n.repeater_packetTxTotal(_packetsSent!, flood, direct); } String _packetRxText() { if (_packetsRecv == null) return '—'; + final l10n = context.l10n; final flood = _formatValue(_floodRx); final direct = _formatValue(_directRx); - return 'Total: $_packetsRecv, Flood: $flood, Direct: $direct'; + return l10n.repeater_packetRxTotal(_packetsRecv!, flood, direct); } String _duplicateText() { + final l10n = context.l10n; if (_dupFlood != null || _dupDirect != null) { final flood = _formatValue(_dupFlood); final direct = _formatValue(_dupDirect); - return 'Flood: $flood, Direct: $direct'; + return l10n.repeater_duplicatesFloodDirect(flood, direct); } if (_packetsRecv == null || _floodRx == null || _directRx == null) return '—'; final dupTotal = _packetsRecv! - _floodRx! - _directRx!; if (dupTotal < 0) return '—'; - return 'Total: $dupTotal'; + return l10n.repeater_duplicatesTotal(dupTotal); } String _formatValue(num? value, {String? suffix}) { diff --git a/lib/screens/scanner_screen.dart b/lib/screens/scanner_screen.dart index a815a3a..63f4a3c 100644 --- a/lib/screens/scanner_screen.dart +++ b/lib/screens/scanner_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:provider/provider.dart'; import '../connector/meshcore_connector.dart'; +import '../l10n/l10n.dart'; import '../widgets/device_tile.dart'; import 'contacts_screen.dart'; @@ -14,7 +15,7 @@ class ScannerScreen extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('MeshCore Open'), + title: Text(context.l10n.scanner_title), centerTitle: true, automaticallyImplyLeading: false, ), @@ -58,7 +59,7 @@ class ScannerScreen extends StatelessWidget { ), ) : const Icon(Icons.bluetooth_searching), - label: Text(isScanning ? 'Stop' : 'Scan'), + label: Text(isScanning ? context.l10n.scanner_stop : context.l10n.scanner_scan), ); }, ), @@ -69,25 +70,26 @@ class ScannerScreen extends StatelessWidget { String statusText; Color statusColor; +final l10n = context.l10n; switch (connector.state) { case MeshCoreConnectionState.scanning: - statusText = 'Scanning for devices...'; + statusText = l10n.scanner_scanning; statusColor = Colors.blue; break; case MeshCoreConnectionState.connecting: - statusText = 'Connecting...'; + statusText = l10n.scanner_connecting; statusColor = Colors.orange; break; case MeshCoreConnectionState.connected: - statusText = 'Connected to ${connector.deviceDisplayName}'; + statusText = l10n.scanner_connectedTo(connector.deviceDisplayName); statusColor = Colors.green; break; case MeshCoreConnectionState.disconnecting: - statusText = 'Disconnecting...'; + statusText = l10n.scanner_disconnecting; statusColor = Colors.orange; break; case MeshCoreConnectionState.disconnected: - statusText = 'Not connected'; + statusText = l10n.scanner_notConnected; statusColor = Colors.grey; break; } @@ -123,8 +125,8 @@ class ScannerScreen extends StatelessWidget { const SizedBox(height: 16), Text( connector.state == MeshCoreConnectionState.scanning - ? 'Searching for MeshCore devices...' - : 'Tap Scan to find MeshCore devices', + ? context.l10n.scanner_searchingDevices + : context.l10n.scanner_tapToScan, style: TextStyle( fontSize: 16, color: Colors.grey[600], @@ -172,7 +174,7 @@ class ScannerScreen extends StatelessWidget { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Connection failed: $e'), + content: Text(context.l10n.scanner_connectionFailed(e.toString())), backgroundColor: Colors.red, ), ); diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 7a08e92..8e23825 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -4,6 +4,7 @@ import 'package:package_info_plus/package_info_plus.dart'; import '../connector/meshcore_connector.dart'; import '../connector/meshcore_protocol.dart'; +import '../l10n/l10n.dart'; import '../models/radio_settings.dart'; import 'app_settings_screen.dart'; import 'app_debug_log_screen.dart'; @@ -18,7 +19,7 @@ class SettingsScreen extends StatefulWidget { class _SettingsScreenState extends State { bool _showBatteryVoltage = false; - String _appVersion = '...'; + String _appVersion = ''; @override void initState() { @@ -35,9 +36,10 @@ class _SettingsScreenState extends State { @override Widget build(BuildContext context) { + final l10n = context.l10n; return Scaffold( appBar: AppBar( - title: const Text('Settings'), + title: Text(l10n.settings_title), centerTitle: true, ), body: SafeArea( @@ -47,7 +49,7 @@ class _SettingsScreenState extends State { return ListView( padding: const EdgeInsets.all(16), children: [ - _buildDeviceInfoCard(connector), + _buildDeviceInfoCard(context, connector), const SizedBox(height: 16), _buildAppSettingsCard(context), const SizedBox(height: 16), @@ -66,46 +68,52 @@ class _SettingsScreenState extends State { ); } - Widget _buildDeviceInfoCard(MeshCoreConnector connector) { + Widget _buildDeviceInfoCard(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'Device Info', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + Text( + l10n.settings_deviceInfo, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 16), - _buildInfoRow('Name', connector.deviceDisplayName), - _buildInfoRow('ID', connector.deviceIdLabel), - _buildInfoRow('Status', connector.isConnected ? 'Connected' : 'Disconnected'), - _buildBatteryInfoRow(connector), + _buildInfoRow(l10n.settings_infoName, connector.deviceDisplayName), + _buildInfoRow(l10n.settings_infoId, connector.deviceIdLabel), + _buildInfoRow(l10n.settings_infoStatus, connector.isConnected ? l10n.common_connected : l10n.common_disconnected), + _buildBatteryInfoRow(context, connector), if (connector.selfName != null) - _buildInfoRow('Node Name', connector.selfName!), + _buildInfoRow(l10n.settings_nodeName, connector.selfName!), if (connector.selfPublicKey != null) - _buildInfoRow('Public Key', '${pubKeyToHex(connector.selfPublicKey!).substring(0, 16)}...'), - _buildInfoRow('Contacts Count', '${connector.contacts.length}'), - _buildInfoRow('Channel Count', '${connector.channels.length}'), + _buildInfoRow(l10n.settings_infoPublicKey, '${pubKeyToHex(connector.selfPublicKey!).substring(0, 16)}...'), + _buildInfoRow(l10n.settings_infoContactsCount, '${connector.contacts.length}'), + _buildInfoRow(l10n.settings_infoChannelCount, '${connector.channels.length}'), ], ), ), ); } - Widget _buildBatteryInfoRow(MeshCoreConnector connector) { + Widget _buildBatteryInfoRow(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; final percent = connector.batteryPercent; final millivolts = connector.batteryMillivolts; // figure out display value final String displayValue; if (millivolts == null) { - displayValue = '—'; + displayValue = l10n.common_notAvailable; } else if (_showBatteryVoltage) { - displayValue = '${(millivolts / 1000.0).toStringAsFixed(2)} V'; + displayValue = l10n.common_voltageValue( + (millivolts / 1000.0).toStringAsFixed(2), + ); } else { - displayValue = percent != null ? '$percent%' : '—'; + displayValue = percent != null + ? l10n.common_percentValue(percent) + : l10n.common_notAvailable; } final IconData icon; @@ -127,7 +135,7 @@ class _SettingsScreenState extends State { } return _buildInfoRow( - 'Battery', + l10n.settings_infoBattery, displayValue, leading: Icon(icon, size: 18, color: iconColor), valueColor: valueColor, @@ -142,11 +150,12 @@ class _SettingsScreenState extends State { } Widget _buildAppSettingsCard(BuildContext context) { + final l10n = context.l10n; return Card( child: ListTile( leading: const Icon(Icons.settings_outlined), - title: const Text('App Settings'), - subtitle: const Text('Notifications, messaging, and map preferences'), + title: Text(l10n.settings_appSettings), + subtitle: Text(l10n.settings_appSettingsSubtitle), trailing: const Icon(Icons.chevron_right), onTap: () { Navigator.push( @@ -159,45 +168,46 @@ class _SettingsScreenState extends State { } Widget _buildNodeSettingsCard(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; return Card( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( - 'Node Settings', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + l10n.settings_nodeSettings, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), ListTile( leading: const Icon(Icons.person_outline), - title: const Text('Node Name'), - subtitle: Text(connector.selfName ?? 'Not set'), + title: Text(l10n.settings_nodeName), + subtitle: Text(connector.selfName ?? l10n.settings_nodeNameNotSet), trailing: const Icon(Icons.chevron_right), onTap: () => _editNodeName(context, connector), ), const Divider(height: 1), ListTile( leading: const Icon(Icons.radio), - title: const Text('Radio Settings'), - subtitle: const Text('Frequency, power, spreading factor'), + title: Text(l10n.settings_radioSettings), + subtitle: Text(l10n.settings_radioSettingsSubtitle), trailing: const Icon(Icons.chevron_right), onTap: () => _showRadioSettings(context, connector), ), const Divider(height: 1), ListTile( leading: const Icon(Icons.location_on_outlined), - title: const Text('Location'), - subtitle: const Text('GPS coordinates'), + title: Text(l10n.settings_location), + subtitle: Text(l10n.settings_locationSubtitle), trailing: const Icon(Icons.chevron_right), onTap: () => _editLocation(context, connector), ), const Divider(height: 1), ListTile( leading: const Icon(Icons.visibility_off_outlined), - title: const Text('Privacy Mode'), - subtitle: const Text('Hide name/location in advertisements'), + title: Text(l10n.settings_privacyMode), + subtitle: Text(l10n.settings_privacyModeSubtitle), trailing: const Icon(Icons.chevron_right), onTap: () => _togglePrivacy(context, connector), ), @@ -207,42 +217,43 @@ class _SettingsScreenState extends State { } Widget _buildActionsCard(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; return Card( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( - 'Actions', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + l10n.settings_actions, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), ListTile( leading: const Icon(Icons.cell_tower), - title: const Text('Send Advertisement'), - subtitle: const Text('Broadcast presence now'), + title: Text(l10n.settings_sendAdvertisement), + subtitle: Text(l10n.settings_sendAdvertisementSubtitle), onTap: () => _sendAdvert(context, connector), ), const Divider(height: 1), ListTile( leading: const Icon(Icons.sync), - title: const Text('Sync Time'), - subtitle: const Text('Set device clock to phone time'), + title: Text(l10n.settings_syncTime), + subtitle: Text(l10n.settings_syncTimeSubtitle), onTap: () => _syncTime(context, connector), ), const Divider(height: 1), ListTile( leading: const Icon(Icons.refresh), - title: const Text('Refresh Contacts'), - subtitle: const Text('Reload contact list from device'), + title: Text(l10n.settings_refreshContacts), + subtitle: Text(l10n.settings_refreshContactsSubtitle), onTap: () => connector.getContacts(), ), const Divider(height: 1), ListTile( leading: const Icon(Icons.restart_alt, color: Colors.orange), - title: const Text('Reboot Device'), - subtitle: const Text('Restart the MeshCore device'), + title: Text(l10n.settings_rebootDevice), + subtitle: Text(l10n.settings_rebootDeviceSubtitle), onTap: () => _confirmReboot(context, connector), ), ], @@ -251,32 +262,38 @@ class _SettingsScreenState extends State { } Widget _buildAboutCard(BuildContext context) { + final l10n = context.l10n; return Card( child: ListTile( leading: const Icon(Icons.info_outline), - title: const Text('About'), - subtitle: Text('MeshCore Open v$_appVersion'), + title: Text(l10n.settings_about), + subtitle: Text( + l10n.settings_aboutVersion( + _appVersion.isEmpty ? l10n.common_loading : _appVersion, + ), + ), onTap: () => _showAbout(context), ), ); } Widget _buildDebugCard(BuildContext context) { + final l10n = context.l10n; return Card( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( - 'Debug', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + l10n.settings_debug, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), ListTile( leading: const Icon(Icons.bluetooth_outlined), - title: const Text('BLE Debug Log'), - subtitle: const Text('BLE commands, responses, and raw data'), + title: Text(l10n.settings_bleDebugLog), + subtitle: Text(l10n.settings_bleDebugLogSubtitle), trailing: const Icon(Icons.chevron_right), onTap: () { Navigator.push( @@ -288,8 +305,8 @@ class _SettingsScreenState extends State { const Divider(height: 1), ListTile( leading: const Icon(Icons.code_outlined), - title: const Text('App Debug Log'), - subtitle: const Text('Application debug messages'), + title: Text(l10n.settings_appDebugLog), + subtitle: Text(l10n.settings_appDebugLogSubtitle), trailing: const Icon(Icons.chevron_right), onTap: () { Navigator.push( @@ -349,23 +366,24 @@ class _SettingsScreenState extends State { } void _editNodeName(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; final controller = TextEditingController(text: connector.selfName ?? ''); showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Node Name'), + title: Text(l10n.settings_nodeName), content: TextField( controller: controller, - decoration: const InputDecoration( - hintText: 'Enter node name', - border: OutlineInputBorder(), + decoration: InputDecoration( + hintText: l10n.settings_nodeNameHint, + border: const OutlineInputBorder(), ), maxLength: 31, ), actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + child: Text(l10n.common_cancel), ), TextButton( onPressed: () async { @@ -374,10 +392,10 @@ class _SettingsScreenState extends State { await connector.refreshDeviceInfo(); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Name updated')), + SnackBar(content: Text(l10n.settings_nodeNameUpdated)), ); }, - child: const Text('Save'), + child: Text(l10n.common_save), ), ], ), @@ -392,29 +410,30 @@ class _SettingsScreenState extends State { } void _editLocation(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; final latController = TextEditingController(); final lonController = TextEditingController(); showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Location'), + title: Text(l10n.settings_location), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: latController, - decoration: const InputDecoration( - labelText: 'Latitude', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.settings_latitude, + border: const OutlineInputBorder(), ), keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true), ), const SizedBox(height: 16), TextField( controller: lonController, - decoration: const InputDecoration( - labelText: 'Longitude', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.settings_longitude, + border: const OutlineInputBorder(), ), keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true), ), @@ -423,7 +442,7 @@ class _SettingsScreenState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + child: Text(l10n.common_cancel), ), TextButton( onPressed: () async { @@ -441,14 +460,14 @@ class _SettingsScreenState extends State { if (lat == null || lon == null) { if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Enter both latitude and longitude.')), + SnackBar(content: Text(l10n.settings_locationBothRequired)), ); return; } if (lat < -90 || lat > 90 || lon < -180 || lon > 180) { if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Invalid latitude or longitude.')), + SnackBar(content: Text(l10n.settings_locationInvalid)), ); return; } @@ -457,10 +476,10 @@ class _SettingsScreenState extends State { await connector.refreshDeviceInfo(); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Location updated')), + SnackBar(content: Text(l10n.settings_locationUpdated)), ); }, - child: const Text('Save'), + child: Text(l10n.common_save), ), ], ), @@ -468,15 +487,16 @@ class _SettingsScreenState extends State { } void _togglePrivacy(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Privacy Mode'), - content: const Text('Toggle privacy mode to hide your name and location in advertisements.'), + title: Text(l10n.settings_privacyMode), + content: Text(l10n.settings_privacyModeToggle), actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + child: Text(l10n.common_cancel), ), TextButton( onPressed: () async { @@ -485,10 +505,10 @@ class _SettingsScreenState extends State { await connector.refreshDeviceInfo(); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Privacy mode enabled')), + SnackBar(content: Text(l10n.settings_privacyModeEnabled)), ); }, - child: const Text('Enable'), + child: Text(l10n.common_enable), ), TextButton( onPressed: () async { @@ -497,10 +517,10 @@ class _SettingsScreenState extends State { await connector.refreshDeviceInfo(); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Privacy mode disabled')), + SnackBar(content: Text(l10n.settings_privacyModeDisabled)), ); }, - child: const Text('Disable'), + child: Text(l10n.common_disable), ), ], ), @@ -508,36 +528,39 @@ class _SettingsScreenState extends State { } void _sendAdvert(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; connector.sendSelfAdvert(flood: true); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Advertisement sent')), + SnackBar(content: Text(l10n.settings_advertisementSent)), ); } void _syncTime(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; connector.syncTime(); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Time synchronized')), + SnackBar(content: Text(l10n.settings_timeSynchronized)), ); } void _confirmReboot(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Reboot Device'), - content: const Text('Are you sure you want to reboot the device? You will be disconnected.'), + title: Text(l10n.settings_rebootDevice), + content: Text(l10n.settings_rebootDeviceConfirm), actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + child: Text(l10n.common_cancel), ), TextButton( onPressed: () { Navigator.pop(context); connector.rebootDevice(); }, - child: const Text('Reboot', style: TextStyle(color: Colors.orange)), + child: Text(l10n.common_reboot, style: const TextStyle(color: Colors.orange)), ), ], ), @@ -545,16 +568,15 @@ class _SettingsScreenState extends State { } void _showAbout(BuildContext context) { + final l10n = context.l10n; showAboutDialog( context: context, - applicationName: 'MeshCore Open', - applicationVersion: _appVersion, - applicationLegalese: '2024 MeshCore Open Source Project', + applicationName: l10n.appTitle, + applicationVersion: _appVersion.isEmpty ? l10n.common_loading : _appVersion, + applicationLegalese: l10n.settings_aboutLegalese, children: [ const SizedBox(height: 16), - const Text( - 'An open-source Flutter client for MeshCore LoRa mesh networking devices.', - ), + Text(l10n.settings_aboutDescription), ], ); } @@ -643,19 +665,20 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { } Future _saveSettings() async { + final l10n = context.l10n; final freqMHz = double.tryParse(_frequencyController.text); final txPower = int.tryParse(_txPowerController.text); if (freqMHz == null || freqMHz < 300 || freqMHz > 2500) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Invalid frequency (300-2500 MHz)')), + SnackBar(content: Text(l10n.settings_frequencyInvalid)), ); return; } if (txPower == null || txPower < 0 || txPower > 22) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Invalid TX power (0-22 dBm)')), + SnackBar(content: Text(l10n.settings_txPowerInvalid)), ); return; } @@ -673,12 +696,12 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { if (!mounted) return; Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Radio settings updated')), + SnackBar(content: Text(l10n.settings_radioSettingsUpdated)), ); } catch (e) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Error: $e')), + SnackBar(content: Text(l10n.settings_error(e.toString()))), ); } } @@ -696,36 +719,37 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { @override Widget build(BuildContext context) { + final l10n = context.l10n; return AlertDialog( - title: const Text('Radio Settings'), + title: Text(l10n.settings_radioSettings), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('Presets', style: TextStyle(fontWeight: FontWeight.bold)), + Text(l10n.settings_presets, style: const TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 8), Wrap( spacing: 8, children: [ _PresetChip( - label: '915 MHz', + label: l10n.settings_preset915Mhz, onTap: () => _applyPreset(RadioSettings.preset915MHz), ), _PresetChip( - label: '868 MHz', + label: l10n.settings_preset868Mhz, onTap: () => _applyPreset(RadioSettings.preset868MHz), ), _PresetChip( - label: '433 MHz', + label: l10n.settings_preset433Mhz, onTap: () => _applyPreset(RadioSettings.preset433MHz), ), _PresetChip( - label: 'Long Range', + label: l10n.settings_longRange, onTap: () => _applyPreset(RadioSettings.presetLongRange), ), _PresetChip( - label: 'Fast Speed', + label: l10n.settings_fastSpeed, onTap: () => _applyPreset(RadioSettings.presetFastSpeed), ), ], @@ -733,19 +757,19 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { const SizedBox(height: 24), TextField( controller: _frequencyController, - decoration: const InputDecoration( - labelText: 'Frequency (MHz)', - border: OutlineInputBorder(), - helperText: '300.0 - 2500.0', + decoration: InputDecoration( + labelText: l10n.settings_frequency, + border: const OutlineInputBorder(), + helperText: l10n.settings_frequencyHelper, ), keyboardType: const TextInputType.numberWithOptions(decimal: true), ), const SizedBox(height: 16), DropdownButtonFormField( initialValue: _bandwidth, - decoration: const InputDecoration( - labelText: 'Bandwidth', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.settings_bandwidth, + border: const OutlineInputBorder(), ), items: LoRaBandwidth.values .map((bw) => DropdownMenuItem( @@ -760,9 +784,9 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { const SizedBox(height: 16), DropdownButtonFormField( initialValue: _spreadingFactor, - decoration: const InputDecoration( - labelText: 'Spreading Factor', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.settings_spreadingFactor, + border: const OutlineInputBorder(), ), items: LoRaSpreadingFactor.values .map((sf) => DropdownMenuItem( @@ -777,9 +801,9 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { const SizedBox(height: 16), DropdownButtonFormField( initialValue: _codingRate, - decoration: const InputDecoration( - labelText: 'Coding Rate', - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: l10n.settings_codingRate, + border: const OutlineInputBorder(), ), items: LoRaCodingRate.values .map((cr) => DropdownMenuItem( @@ -794,10 +818,10 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { const SizedBox(height: 16), TextField( controller: _txPowerController, - decoration: const InputDecoration( - labelText: 'TX Power (dBm)', - border: OutlineInputBorder(), - helperText: '0 - 22', + decoration: InputDecoration( + labelText: l10n.settings_txPower, + border: const OutlineInputBorder(), + helperText: l10n.settings_txPowerHelper, ), keyboardType: TextInputType.number, ), @@ -807,11 +831,11 @@ class _RadioSettingsDialogState extends State<_RadioSettingsDialog> { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + child: Text(l10n.common_cancel), ), FilledButton( onPressed: _saveSettings, - child: const Text('Save'), + child: Text(l10n.common_save), ), ], ); diff --git a/lib/screens/telemetry_screen.dart b/lib/screens/telemetry_screen.dart index 8545e77..f27410d 100644 --- a/lib/screens/telemetry_screen.dart +++ b/lib/screens/telemetry_screen.dart @@ -5,6 +5,7 @@ import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import '../l10n/l10n.dart'; import '../models/contact.dart'; import '../models/path_selection.dart'; import '../connector/meshcore_connector.dart'; @@ -30,7 +31,8 @@ class TelemetryScreen extends StatefulWidget { class _TelemetryScreenState extends State { static const int _statusPayloadOffset = 8; static const int _statusStatsSize = 52; - static const int _statusResponseBytes = _statusPayloadOffset + _statusStatsSize; + static const int _statusResponseBytes = + _statusPayloadOffset + _statusStatsSize; Uint8List _tagData = Uint8List(4); int _timeEstment = 0; @@ -66,7 +68,8 @@ class _TelemetryScreenState extends State { } // Check if it's a binary response - if (frame[0] == pushCodeBinaryResponse && listEquals(frame.sublist(2, 6), _tagData)) { + if (frame[0] == pushCodeBinaryResponse && + listEquals(frame.sublist(2, 6), _tagData)) { _handleStatusResponse(context, frame.sublist(6)); } }); @@ -78,10 +81,10 @@ class _TelemetryScreenState extends State { }); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Received Telemetry Data'), + SnackBar( + content: Text(context.l10n.telemetry_receivedData), backgroundColor: Colors.green, - ) + ), ); _statusTimeout?.cancel(); if (!mounted) return; @@ -111,7 +114,10 @@ class _TelemetryScreenState extends State { final repeater = _resolveRepeater(connector); final selection = await connector.preparePathForContactSend(repeater); _pendingStatusSelection = selection; - final frame = buildSendBinaryReq(repeater.publicKey, payload: Uint8List.fromList([reqTypeGetTelemetry])); + final frame = buildSendBinaryReq( + repeater.publicKey, + payload: Uint8List.fromList([reqTypeGetTelemetry]), + ); await connector.sendFrame(frame); final pathLengthValue = selection.useFlood ? -1 : selection.hopCount; @@ -130,8 +136,8 @@ class _TelemetryScreenState extends State { _isLoaded = false; }); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Telemetry request timed out.'), + SnackBar( + content: Text(context.l10n.telemetry_requestTimeout), backgroundColor: Colors.red, ), ); @@ -146,7 +152,7 @@ class _TelemetryScreenState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Error loading telemetry: $e'), + content: Text(context.l10n.telemetry_errorLoading(e.toString())), backgroundColor: Colors.red, ), ); @@ -173,6 +179,7 @@ class _TelemetryScreenState extends State { @override Widget build(BuildContext context) { + final l10n = context.l10n; final connector = context.watch(); final repeater = _resolveRepeater(connector); final isFloodMode = repeater.pathOverride == -1; @@ -183,10 +190,16 @@ class _TelemetryScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - const Text('Repeater Telemetry', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + Text( + l10n.repeater_telemetry, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), Text( repeater.name, - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.normal), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.normal, + ), ), ], ), @@ -194,7 +207,7 @@ class _TelemetryScreenState extends State { actions: [ PopupMenuButton( icon: Icon(isFloodMode ? Icons.waves : Icons.route), - tooltip: 'Routing mode', + tooltip: l10n.repeater_routingMode, onSelected: (mode) async { if (mode == 'flood') { await connector.setPathOverride(repeater, pathLen: -1); @@ -207,12 +220,20 @@ class _TelemetryScreenState extends State { value: 'auto', child: Row( children: [ - Icon(Icons.auto_mode, size: 20, color: !isFloodMode ? Theme.of(context).primaryColor : null), + Icon( + Icons.auto_mode, + size: 20, + color: !isFloodMode + ? Theme.of(context).primaryColor + : null, + ), const SizedBox(width: 8), Text( - 'Auto (use saved path)', + l10n.repeater_autoUseSavedPath, style: TextStyle( - fontWeight: !isFloodMode ? FontWeight.bold : FontWeight.normal, + fontWeight: !isFloodMode + ? FontWeight.bold + : FontWeight.normal, ), ), ], @@ -222,12 +243,20 @@ class _TelemetryScreenState extends State { value: 'flood', child: Row( children: [ - Icon(Icons.waves, size: 20, color: isFloodMode ? Theme.of(context).primaryColor : null), + Icon( + Icons.waves, + size: 20, + color: isFloodMode + ? Theme.of(context).primaryColor + : null, + ), const SizedBox(width: 8), Text( - 'Force Flood Mode', + l10n.repeater_forceFloodMode, style: TextStyle( - fontWeight: isFloodMode ? FontWeight.bold : FontWeight.normal, + fontWeight: isFloodMode + ? FontWeight.bold + : FontWeight.normal, ), ), ], @@ -237,8 +266,9 @@ class _TelemetryScreenState extends State { ), IconButton( icon: const Icon(Icons.timeline), - tooltip: 'Path management', - onPressed: () => PathManagementDialog.show(context, contact: repeater), + tooltip: l10n.repeater_pathManagement, + onPressed: () => + PathManagementDialog.show(context, contact: repeater), ), IconButton( icon: _isLoading @@ -249,7 +279,7 @@ class _TelemetryScreenState extends State { ) : const Icon(Icons.refresh), onPressed: _isLoading ? null : _loadTelemetry, - tooltip: 'Refresh', + tooltip: l10n.repeater_refresh, ), ], ), @@ -260,16 +290,24 @@ class _TelemetryScreenState extends State { child: ListView( padding: const EdgeInsets.all(16), children: [ - if (!_isLoaded && !_hasData && (_parsedTelemetry == null || _parsedTelemetry!.isEmpty)) - const Center( + if (!_isLoaded && + !_hasData && + (_parsedTelemetry == null || _parsedTelemetry!.isEmpty)) + Center( child: Text( - 'No telemetry data available.', - style: TextStyle(fontSize: 16, color: Colors.grey), + l10n.telemetry_noData, + style: const TextStyle(fontSize: 16, color: Colors.grey), ), ), - if ((_isLoaded || _hasData) && _parsedTelemetry != null && _parsedTelemetry!.isNotEmpty) + if ((_isLoaded || _hasData) && + _parsedTelemetry != null && + _parsedTelemetry!.isNotEmpty) for (final entry in _parsedTelemetry ?? []) - _buildChannelInfoCard(entry['values'], 'Channel ${entry['channel']}', entry['channel']), + _buildChannelInfoCard( + entry['values'], + l10n.telemetry_channelTitle(entry['channel']), + entry['channel'], + ), ], ), ), @@ -277,7 +315,12 @@ class _TelemetryScreenState extends State { ); } - Widget _buildChannelInfoCard(Map channelData, String title, int channel) { + Widget _buildChannelInfoCard( + Map channelData, + String title, + int channel, + ) { + final l10n = context.l10n; return Card( child: Padding( padding: const EdgeInsets.all(16), @@ -286,26 +329,47 @@ class _TelemetryScreenState extends State { children: [ Row( children: [ - Icon(Icons.info_outline, color: Theme.of(context).textTheme.headlineSmall?.color), + Icon( + Icons.info_outline, + color: Theme.of(context).textTheme.headlineSmall?.color, + ), const SizedBox(width: 8), Text( title, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), ), ], ), const Divider(), for (final entry in channelData.entries) if (entry.key == 'voltage' && channel == 1) - _buildInfoRow('Battery', _batteryText(entry.value)) + _buildInfoRow( + l10n.telemetry_batteryLabel, + _batteryText(entry.value), + ) else if (entry.key == 'voltage') - _buildInfoRow('Voltage', '${entry.value}V') + _buildInfoRow( + l10n.telemetry_voltageLabel, + l10n.telemetry_voltageValue(entry.value.toString()), + ) else if (entry.key == 'temperature' && channel == 1) - _buildInfoRow('MCU Temperature', _temperatureText(entry.value)) + _buildInfoRow( + l10n.telemetry_mcuTemperatureLabel, + _temperatureText(entry.value), + ) else if (entry.key == 'temperature') - _buildInfoRow('Temperature', _temperatureText(entry.value)) + _buildInfoRow( + l10n.telemetry_temperatureLabel, + _temperatureText(entry.value), + ) else if (entry.key == 'current' && channel == 1) - _buildInfoRow('Current', '${entry.value}A') + _buildInfoRow( + l10n.telemetry_currentLabel, + l10n.telemetry_currentValue(entry.value.toString()), + ) else _buildInfoRow(entry.key, entry.value.toString()), ], @@ -341,11 +405,12 @@ class _TelemetryScreenState extends State { ); } - String _batteryText(double? _batteryMv) { - if (_batteryMv == null) return '—'; - final percent = _batteryPercentFromMv(_batteryMv); - final volts = _batteryMv.toStringAsFixed(2); - return '$percent% / ${volts}V'; + String _batteryText(double? batteryMv) { + final l10n = context.l10n; + if (batteryMv == null) return l10n.common_notAvailable; + final percent = _batteryPercentFromMv(batteryMv); + final volts = batteryMv.toStringAsFixed(2); + return l10n.telemetry_batteryValue(percent, volts); } int _batteryPercentFromMv(double millivolts) { @@ -357,8 +422,12 @@ class _TelemetryScreenState extends State { } String _temperatureText(double? tempC) { - if (tempC == null) return '—'; + final l10n = context.l10n; + if (tempC == null) return l10n.common_notAvailable; final tempF = (tempC * 9 / 5) + 32; - return '${tempC.toStringAsFixed(1)}°C / ${tempF.toStringAsFixed(1)}°F'; + return l10n.telemetry_temperatureValue( + tempC.toStringAsFixed(1), + tempF.toStringAsFixed(1), + ); } -} \ No newline at end of file +} diff --git a/lib/services/app_settings_service.dart b/lib/services/app_settings_service.dart index 3c7433b..5897943 100644 --- a/lib/services/app_settings_service.dart +++ b/lib/services/app_settings_service.dart @@ -113,6 +113,10 @@ class AppSettingsService extends ChangeNotifier { await updateSettings(_settings.copyWith(themeMode: value)); } + Future setLanguageOverride(String? value) async { + await updateSettings(_settings.copyWith(languageOverride: value)); + } + Future setAppDebugLogEnabled(bool value) async { await updateSettings(_settings.copyWith(appDebugLogEnabled: value)); // Update the global logger diff --git a/lib/utils/dialog_utils.dart b/lib/utils/dialog_utils.dart index 3c89d9c..510eca7 100644 --- a/lib/utils/dialog_utils.dart +++ b/lib/utils/dialog_utils.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../connector/meshcore_connector.dart'; +import '../l10n/l10n.dart'; /// Shows a confirmation dialog before disconnecting from the device. /// Returns true if user confirmed and disconnect completed, false otherwise. @@ -7,20 +8,20 @@ Future showDisconnectDialog( BuildContext context, MeshCoreConnector connector, ) async { + final l10n = context.l10n; final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Disconnect'), - content: const Text( - 'Are you sure you want to disconnect from this device?'), + title: Text(l10n.dialog_disconnect), + content: Text(l10n.dialog_disconnectConfirm), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), - child: const Text('Cancel'), + child: Text(l10n.common_cancel), ), TextButton( onPressed: () => Navigator.pop(context, true), - child: const Text('Disconnect'), + child: Text(l10n.common_disconnect), ), ], ), diff --git a/lib/widgets/debug_frame_viewer.dart b/lib/widgets/debug_frame_viewer.dart index 7c417f9..e2c6e34 100644 --- a/lib/widgets/debug_frame_viewer.dart +++ b/lib/widgets/debug_frame_viewer.dart @@ -1,5 +1,6 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; +import '../l10n/l10n.dart'; import '../connector/meshcore_protocol.dart'; /// Debug widget to show the hex dump of a frame @@ -10,23 +11,32 @@ class DebugFrameViewer { .join(' '); final details = StringBuffer(); - details.writeln('Frame Length: ${frame.length} bytes\n'); - details.writeln('Command: 0x${frame[0].toRadixString(16).padLeft(2, '0')}'); + details.writeln(context.l10n.debugFrame_length(frame.length)); + details.writeln(''); + details.writeln( + context.l10n.debugFrame_command(frame[0].toRadixString(16).padLeft(2, '0')), + ); if (frame[0] == cmdSendTxtMsg && frame.length > 37) { - details.writeln('\nText Message Frame:'); - details.writeln('- Destination PubKey: ${pubKeyToHex(frame.sublist(1, 33))}'); - details.writeln('- Timestamp: ${readUint32LE(frame, 33)}'); - details.writeln('- Flags: 0x${frame[37].toRadixString(16).padLeft(2, '0')}'); + details.writeln(''); + details.writeln(context.l10n.debugFrame_textMessageHeader); + details.writeln(context.l10n.debugFrame_destinationPubKey(pubKeyToHex(frame.sublist(1, 33)))); + details.writeln(context.l10n.debugFrame_timestamp(readUint32LE(frame, 33))); + details.writeln( + context.l10n.debugFrame_flags(frame[37].toRadixString(16).padLeft(2, '0')), + ); final txtType = (frame[37] >> 2) & 0x03; - details.writeln('- Text Type: $txtType ${txtType == txtTypeCliData ? "(CLI)" : "(Plain)"}'); + final typeLabel = txtType == txtTypeCliData + ? context.l10n.debugFrame_textTypeCli + : context.l10n.debugFrame_textTypePlain; + details.writeln(context.l10n.debugFrame_textType(txtType, typeLabel)); if (frame.length > 38) { final textBytes = frame.sublist(38); final nullIdx = textBytes.indexOf(0); final text = String.fromCharCodes( nullIdx >= 0 ? textBytes.sublist(0, nullIdx) : textBytes ); - details.writeln('- Text: "$text"'); + details.writeln(context.l10n.debugFrame_text(text)); } } @@ -44,9 +54,9 @@ class DebugFrameViewer { style: const TextStyle(fontFamily: 'monospace', fontSize: 12), ), const Divider(), - const Text( - 'Hex Dump:', - style: TextStyle(fontWeight: FontWeight.bold), + Text( + context.l10n.debugFrame_hexDump, + style: const TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Text( @@ -59,7 +69,7 @@ class DebugFrameViewer { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Close'), + child: Text(context.l10n.common_close), ), ], ), diff --git a/lib/widgets/device_tile.dart b/lib/widgets/device_tile.dart index 2d6de8d..bbd4faf 100644 --- a/lib/widgets/device_tile.dart +++ b/lib/widgets/device_tile.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; +import '../l10n/l10n.dart'; /// A reusable tile widget for displaying a MeshCore device in a list class DeviceTile extends StatelessWidget { @@ -23,13 +24,13 @@ class DeviceTile extends StatelessWidget { return ListTile( leading: _buildSignalIcon(rssi), title: Text( - name.isNotEmpty ? name : 'Unknown Device', + name.isNotEmpty ? name : context.l10n.common_unknownDevice, style: const TextStyle(fontWeight: FontWeight.w500), ), subtitle: Text(device.remoteId.toString()), trailing: ElevatedButton( onPressed: onTap, - child: const Text('Connect'), + child: Text(context.l10n.common_connect), ), onTap: onTap, ); diff --git a/lib/widgets/emoji_picker.dart b/lib/widgets/emoji_picker.dart index 06bc98b..1a2ffa3 100644 --- a/lib/widgets/emoji_picker.dart +++ b/lib/widgets/emoji_picker.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import '../l10n/app_localizations.dart'; +import '../l10n/l10n.dart'; class EmojiPicker extends StatelessWidget { final Function(String) onEmojiSelected; @@ -10,30 +12,39 @@ class EmojiPicker extends StatelessWidget { static const List quickEmojis = ['👍', '❤️', '😂', '🎉', '👏', '🔥']; - static const Map> emojiCategories = { - 'Smileys': [ + static const List _smileys = [ '😀', '😃', '😄', '😁', '😅', '😂', '🤣', '😊', '😇', '🙂', '🙃', '😉', '😌', '😍', '🥰', '😘', '😗', '😙', '😚', '😋', '😛', '😝', '😜', '🤪', '🤨', '🧐', '🤓', '😎', '🥸', '🤩', '🥳', '😏', '😒', '😞', '😔', '😟', '😕', '🙁', '😣', '😖', '😫', '😩', '🥺', '😢', '😭', '😤', '😠', '😡', '🤬', '🤯', '😳', '🥵', '🥶', '😱', '😨', '😰', '😥', '😓', '🤗', '🤔', '🤭', '🤫', '🤥', '😶', - ], - 'Gestures': [ + ]; + static const List _gestures = [ '👍', '👎', '👊', '✊', '🤛', '🤜', '🤞', '✌️', '🤟', '🤘', '👌', '🤌', '🤏', '👈', '👉', '👆', '👇', '☝️', '👋', '🤚', '🖐️', '✋', '🖖', '👏', '🙌', '👐', '🤲', '🤝', '🙏', '✍️', '💅', '🤳', - ], - 'Hearts': [ + ]; + static const List _hearts = [ '❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎', '💔', '❤️‍🔥', '❤️‍🩹', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟', '💌', '💢', '💥', '💫', '💦', '💨', '🕳️', '💬', '👁️‍🗨️', '🗨️', '🗯️', '💭', - ], - 'Objects': [ + ]; + static const List _objects = [ '🎉', '🎊', '🎈', '🎁', '🎀', '🪅', '🪆', '🏆', '🥇', '🥈', '🥉', '⚽', '⚾', '🥎', '🏀', '🏐', '🏈', '🏉', '🎾', '🥏', '🎳', '🏏', '🏑', '🏒', '🥍', '🏓', '🏸', '🥊', '🥋', '🥅', '⛳', '🔥', '⭐', '🌟', '✨', '⚡', '💡', '🔦', '🏮', '🪔', '📱', '💻', '⌚', '📷', '📺', '📻', '🎵', '🎶', - ], - }; + ]; + + Map> _emojiCategories(AppLocalizations l10n) { + return { + l10n.emojiCategorySmileys: _smileys, + l10n.emojiCategoryGestures: _gestures, + l10n.emojiCategoryHearts: _hearts, + l10n.emojiCategoryObjects: _objects, + }; + } @override Widget build(BuildContext context) { + final l10n = context.l10n; + final emojiCategories = _emojiCategories(l10n); return Container( height: MediaQuery.of(context).size.height * 0.5, decoration: BoxDecoration( @@ -47,9 +58,9 @@ class EmojiPicker extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const Text( - 'Add Reaction', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + Text( + l10n.chat_addReaction, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), IconButton( icon: const Icon(Icons.close), diff --git a/lib/widgets/gif_picker.dart b/lib/widgets/gif_picker.dart index 94a75bf..df0a6f7 100644 --- a/lib/widgets/gif_picker.dart +++ b/lib/widgets/gif_picker.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; +import '../l10n/l10n.dart'; class GifPicker extends StatefulWidget { final Function(String gifId) onGifSelected; @@ -57,14 +58,16 @@ class _GifPickerState extends State { _isLoading = false; }); } else { + if (!mounted) return; setState(() { - _error = 'Failed to load GIFs'; + _error = context.l10n.gifPicker_failedLoad; _isLoading = false; }); } } catch (e) { + if (!mounted) return; setState(() { - _error = 'No internet connection'; + _error = context.l10n.gifPicker_noInternet; _isLoading = false; }); } @@ -95,14 +98,16 @@ class _GifPickerState extends State { _isLoading = false; }); } else { + if (!mounted) return; setState(() { - _error = 'Failed to search GIFs'; + _error = context.l10n.gifPicker_failedSearch; _isLoading = false; }); } } catch (e) { + if (!mounted) return; setState(() { - _error = 'No internet connection'; + _error = context.l10n.gifPicker_noInternet; _isLoading = false; }); } @@ -120,9 +125,9 @@ class _GifPickerState extends State { children: [ const Icon(Icons.gif_box, size: 28), const SizedBox(width: 8), - const Text( - 'Choose a GIF', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + Text( + context.l10n.gifPicker_title, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const Spacer(), IconButton( @@ -137,7 +142,7 @@ class _GifPickerState extends State { TextField( controller: _searchController, decoration: InputDecoration( - hintText: 'Search GIFs...', + hintText: context.l10n.gifPicker_searchHint, prefixIcon: const Icon(Icons.search), suffixIcon: _searchController.text.isNotEmpty ? IconButton( @@ -172,7 +177,7 @@ class _GifPickerState extends State { // Powered by Giphy attribution const SizedBox(height: 8), Text( - 'Powered by GIPHY', + context.l10n.gifPicker_poweredBy, style: TextStyle( fontSize: 11, color: Colors.grey[600], @@ -205,7 +210,7 @@ class _GifPickerState extends State { ElevatedButton.icon( onPressed: _loadTrendingGifs, icon: const Icon(Icons.refresh), - label: const Text('Retry'), + label: Text(context.l10n.common_retry), ), ], ), @@ -220,7 +225,7 @@ class _GifPickerState extends State { Icon(Icons.search_off, size: 64, color: Colors.grey[400]), const SizedBox(height: 16), Text( - 'No GIFs found', + context.l10n.gifPicker_noGifsFound, style: TextStyle(fontSize: 16, color: Colors.grey[600]), ), ], diff --git a/lib/widgets/list_filter_widget.dart b/lib/widgets/list_filter_widget.dart index fad54b3..97ca3e7 100644 --- a/lib/widgets/list_filter_widget.dart +++ b/lib/widgets/list_filter_widget.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../l10n/l10n.dart'; enum ContactSortOption { lastSeen, @@ -45,7 +46,7 @@ class SortFilterMenu extends StatelessWidget { super.key, required this.sections, required this.onSelected, - this.tooltip = 'Filter and sort', + required this.tooltip, this.icon = const Icon(Icons.filter_list_outlined), }); @@ -131,59 +132,61 @@ class ContactsFilterMenu extends StatelessWidget { @override Widget build(BuildContext context) { + final l10n = context.l10n; return SortFilterMenu( + tooltip: l10n.listFilter_tooltip, sections: [ SortFilterMenuSection( - title: 'Sort by', + title: l10n.listFilter_sortBy, options: [ SortFilterMenuOption( value: _actionSortRecentMessages, - label: 'Latest messages', + label: l10n.listFilter_latestMessages, checked: sortOption == ContactSortOption.recentMessages, ), SortFilterMenuOption( value: _actionSortLastSeen, - label: 'Heard recently', + label: l10n.listFilter_heardRecently, checked: sortOption == ContactSortOption.lastSeen, ), SortFilterMenuOption( value: _actionSortName, - label: 'A-Z', + label: l10n.listFilter_az, checked: sortOption == ContactSortOption.name, ), ], ), SortFilterMenuSection( - title: 'Filters', + title: l10n.listFilter_filters, options: [ SortFilterMenuOption( value: _actionFilterAll, - label: 'All', + label: l10n.listFilter_all, checked: typeFilter == ContactTypeFilter.all, ), SortFilterMenuOption( value: _actionFilterUsers, - label: 'Users', + label: l10n.listFilter_users, checked: typeFilter == ContactTypeFilter.users, ), SortFilterMenuOption( value: _actionFilterRepeaters, - label: 'Repeaters', + label: l10n.listFilter_repeaters, checked: typeFilter == ContactTypeFilter.repeaters, ), SortFilterMenuOption( value: _actionFilterRooms, - label: 'Room servers', + label: l10n.listFilter_roomServers, checked: typeFilter == ContactTypeFilter.rooms, ), SortFilterMenuOption( value: _actionToggleUnreadOnly, - label: 'Unread only', + label: l10n.listFilter_unreadOnly, checked: showUnreadOnly, ), - const SortFilterMenuOption( + SortFilterMenuOption( value: _actionNewGroup, - label: 'New group', + label: l10n.listFilter_newGroup, ), ], ), diff --git a/lib/widgets/path_management_dialog.dart b/lib/widgets/path_management_dialog.dart index 0a25e31..00fc083 100644 --- a/lib/widgets/path_management_dialog.dart +++ b/lib/widgets/path_management_dialog.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../connector/meshcore_connector.dart'; +import '../l10n/l10n.dart'; import '../models/contact.dart'; import '../services/path_history_service.dart'; import 'path_selection_dialog.dart'; @@ -12,13 +13,11 @@ class PathManagementDialog { static Future show( BuildContext context, { required Contact contact, - String title = 'Path Management', }) { return showDialog( context: context, builder: (context) => _PathManagementDialog( contact: contact, - title: title, ), ); } @@ -26,11 +25,9 @@ class PathManagementDialog { class _PathManagementDialog extends StatelessWidget { final Contact contact; - final String title; const _PathManagementDialog({ required this.contact, - required this.title, }); Contact _resolveContact(MeshCoreConnector connector) { @@ -40,20 +37,22 @@ class _PathManagementDialog extends StatelessWidget { ); } - String _formatRelativeTime(DateTime time) { + String _formatRelativeTime(BuildContext context, DateTime time) { + final l10n = context.l10n; final diff = DateTime.now().difference(time); - if (diff.inSeconds < 60) return 'Just now'; - if (diff.inMinutes < 60) return '${diff.inMinutes}m ago'; - if (diff.inHours < 24) return '${diff.inHours}h ago'; - return '${diff.inDays}d ago'; + if (diff.inSeconds < 60) return l10n.time_justNow; + if (diff.inMinutes < 60) return l10n.time_minutesAgo(diff.inMinutes); + if (diff.inHours < 24) return l10n.time_hoursAgo(diff.inHours); + return l10n.time_daysAgo(diff.inDays); } void _showFullPathDialog(BuildContext context, List pathBytes) { + final l10n = context.l10n; if (pathBytes.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Path details not available yet. Try sending a message to refresh.'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(l10n.chat_pathDetailsNotAvailable), + duration: const Duration(seconds: 2), ), ); return; @@ -66,12 +65,12 @@ class _PathManagementDialog extends StatelessWidget { showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Full Path'), + title: Text(l10n.chat_fullPath), content: SelectableText(formattedPath), actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Close'), + child: Text(l10n.common_close), ), ], ), @@ -83,6 +82,7 @@ class _PathManagementDialog extends StatelessWidget { MeshCoreConnector connector, Contact currentContact, ) async { + final l10n = context.l10n; if (currentContact.pathLength > 0 && currentContact.path.isEmpty && connector.isConnected) { connector.getContacts(); } @@ -96,7 +96,6 @@ class _PathManagementDialog extends StatelessWidget { context, availableContacts: availableContacts, initialPath: pathForInput.isEmpty ? null : pathForInput, - title: 'Set Custom Path', currentPathLabel: currentContact.pathLabel, onRefresh: connector.isConnected ? connector.getContacts : null, ); @@ -111,7 +110,7 @@ class _PathManagementDialog extends StatelessWidget { if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Path set: ${result.length} ${result.length == 1 ? "hop" : "hops"}'), + content: Text(l10n.chat_hopsCount(result.length)), duration: const Duration(seconds: 2), ), ); @@ -120,27 +119,28 @@ class _PathManagementDialog extends StatelessWidget { @override Widget build(BuildContext context) { + final l10n = context.l10n; return Consumer2( builder: (context, connector, pathService, _) { final currentContact = _resolveContact(connector); final paths = pathService.getRecentPaths(currentContact.publicKeyHex); return AlertDialog( - title: Text(title), + title: Text(l10n.chat_pathManagement), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Current path: ${currentContact.pathLabel}', + l10n.path_currentPath(currentContact.pathLabel), style: const TextStyle(fontSize: 12, color: Colors.grey), ), const SizedBox(height: 12), if (paths.isNotEmpty) ...[ - const Text( - 'Recent ACK Paths (tap to use):', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), + Text( + l10n.chat_recentAckPaths, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12), ), if (paths.length >= 100) ...[ const SizedBox(height: 8), @@ -151,9 +151,9 @@ class _PathManagementDialog extends StatelessWidget { color: Colors.amberAccent, borderRadius: BorderRadius.circular(8), ), - child: const Text( - 'Path history is full. Remove entries to add new ones.', - style: TextStyle(fontSize: 12), + child: Text( + l10n.chat_pathHistoryFull, + style: const TextStyle(fontSize: 12), ), ), ], @@ -172,11 +172,11 @@ class _PathManagementDialog extends StatelessWidget { ), ), title: Text( - '${path.hopCount} ${path.hopCount == 1 ? 'hop' : 'hops'}', + l10n.chat_hopsCount(path.hopCount), style: const TextStyle(fontSize: 14), ), subtitle: Text( - '${(path.tripTimeMs / 1000).toStringAsFixed(2)}s • ${_formatRelativeTime(path.timestamp)} • ${path.successCount} successes', + '${(path.tripTimeMs / 1000).toStringAsFixed(2)}s • ${_formatRelativeTime(context, path.timestamp)} • ${path.successCount} ${l10n.chat_successes}', style: const TextStyle(fontSize: 11), ), trailing: Row( @@ -184,7 +184,7 @@ class _PathManagementDialog extends StatelessWidget { children: [ IconButton( icon: const Icon(Icons.close, size: 16), - tooltip: 'Remove path', + tooltip: l10n.chat_removePath, onPressed: () async { await pathService.removePathRecord( currentContact.publicKeyHex, @@ -201,9 +201,9 @@ class _PathManagementDialog extends StatelessWidget { onTap: () async { if (path.pathBytes.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Path details not available yet. Try sending a message to refresh.'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(l10n.chat_pathDetailsNotAvailable), + duration: const Duration(seconds: 2), ), ); return; @@ -222,7 +222,7 @@ class _PathManagementDialog extends StatelessWidget { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Using ${path.hopCount} ${path.hopCount == 1 ? 'hop' : 'hops'} path'), + content: Text(l10n.path_usingHopsPath(path.hopCount)), duration: const Duration(seconds: 2), ), ); @@ -232,13 +232,13 @@ class _PathManagementDialog extends StatelessWidget { }), const Divider(), ] else ...[ - const Text('No path history yet.\nSend a message to discover paths.'), + Text(l10n.chat_noPathHistoryYet), const Divider(), ], const SizedBox(height: 8), - const Text( - 'Path Actions:', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), + Text( + l10n.chat_pathActions, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12), ), const SizedBox(height: 8), ListTile( @@ -248,8 +248,8 @@ class _PathManagementDialog extends StatelessWidget { backgroundColor: Colors.purple, child: Icon(Icons.edit_road, size: 16), ), - title: const Text('Set Custom Path', style: TextStyle(fontSize: 14)), - subtitle: const Text('Manually specify routing path', style: TextStyle(fontSize: 11)), + title: Text(l10n.chat_setCustomPath, style: const TextStyle(fontSize: 14)), + subtitle: Text(l10n.chat_setCustomPathSubtitle, style: const TextStyle(fontSize: 11)), onTap: () async { await _setCustomPath(context, connector, currentContact); }, @@ -261,15 +261,15 @@ class _PathManagementDialog extends StatelessWidget { backgroundColor: Colors.orange, child: Icon(Icons.clear_all, size: 16), ), - title: const Text('Clear Path', style: TextStyle(fontSize: 14)), - subtitle: const Text('Force rediscovery on next send', style: TextStyle(fontSize: 11)), + title: Text(l10n.chat_clearPath, style: const TextStyle(fontSize: 14)), + subtitle: Text(l10n.chat_clearPathSubtitle, style: const TextStyle(fontSize: 11)), onTap: () async { await connector.clearContactPath(currentContact); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Path cleared. Next message will rediscover route.'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(l10n.chat_pathCleared), + duration: const Duration(seconds: 2), ), ); Navigator.pop(context); @@ -282,15 +282,15 @@ class _PathManagementDialog extends StatelessWidget { backgroundColor: Colors.blue, child: Icon(Icons.waves, size: 16), ), - title: const Text('Force Flood Mode', style: TextStyle(fontSize: 14)), - subtitle: const Text('Use routing toggle in app bar', style: TextStyle(fontSize: 11)), + title: Text(l10n.chat_forceFloodMode, style: const TextStyle(fontSize: 14)), + subtitle: Text(l10n.chat_floodModeSubtitle, style: const TextStyle(fontSize: 11)), onTap: () async { await connector.setPathOverride(currentContact, pathLen: -1); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Flood mode enabled. Toggle back via routing icon in app bar.'), - duration: Duration(seconds: 2), + SnackBar( + content: Text(l10n.chat_floodModeEnabled), + duration: const Duration(seconds: 2), ), ); Navigator.pop(context); @@ -302,7 +302,7 @@ class _PathManagementDialog extends StatelessWidget { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Close'), + child: Text(l10n.common_close), ), ], ); diff --git a/lib/widgets/path_selection_dialog.dart b/lib/widgets/path_selection_dialog.dart index 6496635..5a5aa59 100644 --- a/lib/widgets/path_selection_dialog.dart +++ b/lib/widgets/path_selection_dialog.dart @@ -1,19 +1,20 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; +import '../l10n/l10n.dart'; import '../models/contact.dart'; class PathSelectionDialog extends StatefulWidget { final List availableContacts; - final String? initialPath; final String title; + final String? initialPath; final String? currentPathLabel; final VoidCallback? onRefresh; const PathSelectionDialog({ super.key, required this.availableContacts, + required this.title, this.initialPath, - this.title = 'Enter Custom Path', this.currentPathLabel, this.onRefresh, }); @@ -24,8 +25,8 @@ class PathSelectionDialog extends StatefulWidget { static Future show( BuildContext context, { required List availableContacts, + String? title, String? initialPath, - String title = 'Enter Custom Path', String? currentPathLabel, VoidCallback? onRefresh, }) { @@ -33,8 +34,8 @@ class PathSelectionDialog extends StatefulWidget { context: context, builder: (context) => PathSelectionDialog( availableContacts: availableContacts, + title: title ?? context.l10n.path_enterCustomPath, initialPath: initialPath, - title: title, currentPathLabel: currentPathLabel, onRefresh: onRefresh, ), @@ -98,6 +99,7 @@ class _PathSelectionDialogState extends State { } Future _validateAndSubmit() async { + final l10n = context.l10n; final path = _controller.text.trim().toUpperCase(); if (path.isEmpty) { if (mounted) Navigator.pop(context); @@ -130,7 +132,7 @@ class _PathSelectionDialogState extends State { if (invalidPrefixes.isNotEmpty) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Invalid hex prefixes: ${invalidPrefixes.join(", ")}'), + content: Text(l10n.path_invalidHexPrefixes(invalidPrefixes.join(", "))), duration: const Duration(seconds: 3), backgroundColor: Colors.red, ), @@ -141,9 +143,9 @@ class _PathSelectionDialogState extends State { // Check max path length (64 hops) if (pathBytesList.length > 64) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Path too long. Maximum 64 hops allowed.'), - duration: Duration(seconds: 3), + SnackBar( + content: Text(l10n.path_tooLong), + duration: const Duration(seconds: 3), backgroundColor: Colors.red, ), ); @@ -163,6 +165,7 @@ class _PathSelectionDialogState extends State { @override Widget build(BuildContext context) { + final l10n = context.l10n; return AlertDialog( title: Text(widget.title), content: SingleChildScrollView( @@ -175,16 +178,16 @@ class _PathSelectionDialogState extends State { if (widget.currentPathLabel != null) ...[ Row( children: [ - const Text( - 'Current path', - style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold), + Text( + l10n.path_currentPathLabel, + style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold), ), const Spacer(), if (widget.onRefresh != null) TextButton.icon( onPressed: widget.onRefresh, icon: const Icon(Icons.refresh, size: 16), - label: const Text('Reload'), + label: Text(l10n.common_reload), ), ], ), @@ -194,23 +197,23 @@ class _PathSelectionDialogState extends State { ), const SizedBox(height: 16), ], - const Text( - 'Enter 2-character hex prefixes for each hop, separated by commas.', - style: TextStyle(fontSize: 12, color: Colors.grey), + Text( + l10n.path_hexPrefixInstructions, + style: const TextStyle(fontSize: 12, color: Colors.grey), ), const SizedBox(height: 8), - const Text( - 'Example: A1,F2,3C (each node uses first byte of its public key)', - style: TextStyle(fontSize: 11, color: Colors.grey), + Text( + l10n.path_hexPrefixExample, + style: const TextStyle(fontSize: 11, color: Colors.grey), ), const SizedBox(height: 16), TextField( controller: _controller, - decoration: const InputDecoration( - labelText: 'Path (hex prefixes)', - hintText: 'A1,F2,3C', - border: OutlineInputBorder(), - helperText: 'Max 64 hops. Each prefix is 2 hex characters (1 byte)', + decoration: InputDecoration( + labelText: l10n.path_labelHexPrefixes, + hintText: l10n.path_hexPrefixExample, + border: const OutlineInputBorder(), + helperText: l10n.path_helperMaxHops, ), textCapitalization: TextCapitalization.characters, maxLength: 191, // 64 hops * 2 chars + 63 commas @@ -220,36 +223,36 @@ class _PathSelectionDialogState extends State { const SizedBox(height: 8), Row( children: [ - const Text( - 'Or select from contacts:', - style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold), + Text( + l10n.path_selectFromContacts, + style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold), ), const Spacer(), if (_selectedContacts.isNotEmpty) TextButton( onPressed: _clearSelection, - child: const Text('Clear'), + child: Text(l10n.common_clear), ), ], ), const SizedBox(height: 8), if (_validContacts.isEmpty) ...[ - const Center( + Center( child: Padding( - padding: EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16.0), child: Column( children: [ - Icon(Icons.info_outline, size: 48, color: Colors.grey), - SizedBox(height: 16), + const Icon(Icons.info_outline, size: 48, color: Colors.grey), + const SizedBox(height: 16), Text( - 'No repeaters or room servers found.', - style: TextStyle(fontSize: 14), + l10n.path_noRepeatersFound, + style: const TextStyle(fontSize: 14), textAlign: TextAlign.center, ), - SizedBox(height: 8), + const SizedBox(height: 8), Text( - 'Custom paths require intermediate hops that can relay messages.', - style: TextStyle(fontSize: 12, color: Colors.grey), + l10n.path_customPathsRequire, + style: const TextStyle(fontSize: 12, color: Colors.grey), textAlign: TextAlign.center, ), ], @@ -300,11 +303,11 @@ class _PathSelectionDialogState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + child: Text(l10n.common_cancel), ), TextButton( onPressed: _validateAndSubmit, - child: const Text('Set Path'), + child: Text(l10n.path_setPath), ), ], ); diff --git a/lib/widgets/quick_switch_bar.dart b/lib/widgets/quick_switch_bar.dart index 4f13a2f..134091f 100644 --- a/lib/widgets/quick_switch_bar.dart +++ b/lib/widgets/quick_switch_bar.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import '../l10n/l10n.dart'; class QuickSwitchBar extends StatelessWidget { final int selectedIndex; @@ -59,18 +60,18 @@ class QuickSwitchBar extends StatelessWidget { height: 60, selectedIndex: selectedIndex, onDestinationSelected: onDestinationSelected, - destinations: const [ + destinations: [ NavigationDestination( - icon: Icon(Icons.people_outline), - label: 'Contacts', + icon: const Icon(Icons.people_outline), + label: context.l10n.nav_contacts, ), NavigationDestination( - icon: Icon(Icons.tag), - label: 'Channels', + icon: const Icon(Icons.tag), + label: context.l10n.nav_channels, ), NavigationDestination( - icon: Icon(Icons.map_outlined), - label: 'Map', + icon: const Icon(Icons.map_outlined), + label: context.l10n.nav_map, ), ], ), diff --git a/lib/widgets/repeater_login_dialog.dart b/lib/widgets/repeater_login_dialog.dart index 91d6785..50ff0e3 100644 --- a/lib/widgets/repeater_login_dialog.dart +++ b/lib/widgets/repeater_login_dialog.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:provider/provider.dart'; +import '../l10n/l10n.dart'; import '../models/contact.dart'; import '../services/storage_service.dart'; import '../connector/meshcore_connector.dart'; @@ -181,7 +182,7 @@ class _RepeaterLoginDialogState extends State { }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Login failed: $e'), + content: Text(context.l10n.login_failed(e.toString())), backgroundColor: Colors.red, ), ); @@ -223,6 +224,7 @@ class _RepeaterLoginDialogState extends State { @override Widget build(BuildContext context) { + final l10n = context.l10n; final connector = context.watch(); final repeater = _resolveRepeater(connector); final isFloodMode = repeater.pathOverride == -1; @@ -235,7 +237,7 @@ class _RepeaterLoginDialogState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('Repeater Login'), + Text(l10n.login_repeaterLogin), Text( repeater.name, style: TextStyle( @@ -260,17 +262,17 @@ class _RepeaterLoginDialogState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'Enter the repeater password to access settings and status.', - style: TextStyle(fontSize: 14), + Text( + l10n.login_repeaterDescription, + style: const TextStyle(fontSize: 14), ), const SizedBox(height: 16), TextField( controller: _passwordController, obscureText: _obscurePassword, decoration: InputDecoration( - labelText: 'Password', - hintText: 'Enter password', + labelText: l10n.login_password, + hintText: l10n.login_enterPassword, border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.lock), suffixIcon: IconButton( @@ -297,13 +299,13 @@ class _RepeaterLoginDialogState extends State { _savePassword = value ?? false; }); }, - title: const Text( - 'Save password', - style: TextStyle(fontSize: 14), + title: Text( + l10n.login_savePassword, + style: const TextStyle(fontSize: 14), ), - subtitle: const Text( - 'Password will be stored securely on this device', - style: TextStyle(fontSize: 12), + subtitle: Text( + l10n.login_savePasswordSubtitle, + style: const TextStyle(fontSize: 12), ), controlAffinity: ListTileControlAffinity.leading, contentPadding: EdgeInsets.zero, @@ -311,14 +313,14 @@ class _RepeaterLoginDialogState extends State { const Divider(), Row( children: [ - const Text( - 'Routing', - style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold), + Text( + l10n.login_routing, + style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold), ), const Spacer(), PopupMenuButton( icon: Icon(isFloodMode ? Icons.waves : Icons.route), - tooltip: 'Routing mode', + tooltip: l10n.login_routingMode, onSelected: (mode) async { if (mode == 'flood') { await connector.setPathOverride(repeater, pathLen: -1); @@ -334,7 +336,7 @@ class _RepeaterLoginDialogState extends State { Icon(Icons.auto_mode, size: 20, color: !isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Auto (use saved path)', + l10n.login_autoUseSavedPath, style: TextStyle( fontWeight: !isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -349,7 +351,7 @@ class _RepeaterLoginDialogState extends State { Icon(Icons.waves, size: 20, color: isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Force Flood Mode', + l10n.login_forceFloodMode, style: TextStyle( fontWeight: isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -372,7 +374,7 @@ class _RepeaterLoginDialogState extends State { child: TextButton.icon( onPressed: () => PathManagementDialog.show(context, contact: repeater), icon: const Icon(Icons.timeline, size: 18), - label: const Text('Manage Paths'), + label: Text(l10n.login_managePaths), ), ), ], @@ -380,7 +382,7 @@ class _RepeaterLoginDialogState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + child: Text(l10n.common_cancel), ), if (_isLoggingIn) SizedBox( @@ -399,7 +401,7 @@ class _RepeaterLoginDialogState extends State { ), ), const SizedBox(width: 12), - Text('Attempt $_currentAttempt/$_maxAttempts'), + Text(l10n.login_attempt(_currentAttempt, _maxAttempts)), ], ), ), @@ -408,7 +410,7 @@ class _RepeaterLoginDialogState extends State { FilledButton.icon( onPressed: _isLoading ? null : _handleLogin, icon: const Icon(Icons.login, size: 18), - label: const Text('Login'), + label: Text(l10n.login_login), ), ], ); diff --git a/lib/widgets/room_login_dialog.dart b/lib/widgets/room_login_dialog.dart index dc4592d..dd179f8 100644 --- a/lib/widgets/room_login_dialog.dart +++ b/lib/widgets/room_login_dialog.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:provider/provider.dart'; +import '../l10n/l10n.dart'; import '../models/contact.dart'; import '../services/storage_service.dart'; import '../connector/meshcore_connector.dart'; @@ -181,7 +182,7 @@ class _RoomLoginDialogState extends State { }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Login failed: $e'), + content: Text(context.l10n.login_failed(e.toString())), backgroundColor: Colors.red, ), ); @@ -223,6 +224,7 @@ class _RoomLoginDialogState extends State { @override Widget build(BuildContext context) { + final l10n = context.l10n; final connector = context.watch(); final repeater = _resolveRepeater(connector); final isFloodMode = repeater.pathOverride == -1; @@ -235,7 +237,7 @@ class _RoomLoginDialogState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('Room Login'), + Text(l10n.login_roomLogin), Text( repeater.name, style: TextStyle( @@ -260,17 +262,17 @@ class _RoomLoginDialogState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'Enter the room password to access settings and status.', - style: TextStyle(fontSize: 14), + Text( + l10n.login_roomDescription, + style: const TextStyle(fontSize: 14), ), const SizedBox(height: 16), TextField( controller: _passwordController, obscureText: _obscurePassword, decoration: InputDecoration( - labelText: 'Password', - hintText: 'Enter password', + labelText: l10n.login_password, + hintText: l10n.login_enterPassword, border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.lock), suffixIcon: IconButton( @@ -297,13 +299,13 @@ class _RoomLoginDialogState extends State { _savePassword = value ?? false; }); }, - title: const Text( - 'Save password', - style: TextStyle(fontSize: 14), + title: Text( + l10n.login_savePassword, + style: const TextStyle(fontSize: 14), ), - subtitle: const Text( - 'Password will be stored securely on this device', - style: TextStyle(fontSize: 12), + subtitle: Text( + l10n.login_savePasswordSubtitle, + style: const TextStyle(fontSize: 12), ), controlAffinity: ListTileControlAffinity.leading, contentPadding: EdgeInsets.zero, @@ -311,14 +313,14 @@ class _RoomLoginDialogState extends State { const Divider(), Row( children: [ - const Text( - 'Routing', - style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold), + Text( + l10n.login_routing, + style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold), ), const Spacer(), PopupMenuButton( icon: Icon(isFloodMode ? Icons.waves : Icons.route), - tooltip: 'Routing mode', + tooltip: l10n.login_routingMode, onSelected: (mode) async { if (mode == 'flood') { await connector.setPathOverride(repeater, pathLen: -1); @@ -334,7 +336,7 @@ class _RoomLoginDialogState extends State { Icon(Icons.auto_mode, size: 20, color: !isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Auto (use saved path)', + l10n.login_autoUseSavedPath, style: TextStyle( fontWeight: !isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -349,7 +351,7 @@ class _RoomLoginDialogState extends State { Icon(Icons.waves, size: 20, color: isFloodMode ? Theme.of(context).primaryColor : null), const SizedBox(width: 8), Text( - 'Force Flood Mode', + l10n.login_forceFloodMode, style: TextStyle( fontWeight: isFloodMode ? FontWeight.bold : FontWeight.normal, ), @@ -372,7 +374,7 @@ class _RoomLoginDialogState extends State { child: TextButton.icon( onPressed: () => PathManagementDialog.show(context, contact: repeater), icon: const Icon(Icons.timeline, size: 18), - label: const Text('Manage Paths'), + label: Text(l10n.login_managePaths), ), ), ], @@ -380,7 +382,7 @@ class _RoomLoginDialogState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Cancel'), + child: Text(l10n.common_cancel), ), if (_isLoggingIn) SizedBox( @@ -399,7 +401,7 @@ class _RoomLoginDialogState extends State { ), ), const SizedBox(width: 12), - Text('Attempt $_currentAttempt/$_maxAttempts'), + Text(l10n.login_attempt(_currentAttempt, _maxAttempts)), ], ), ), @@ -408,7 +410,7 @@ class _RoomLoginDialogState extends State { FilledButton.icon( onPressed: _isLoading ? null : _handleLogin, icon: const Icon(Icons.login, size: 18), - label: const Text('Login'), + label: Text(l10n.login_login), ), ], ); diff --git a/pubspec.lock b/pubspec.lock index d8c54e8..ef56ad0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -294,6 +294,11 @@ packages: url: "https://pub.dev" source: hosted version: "8.0.0" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_map: dependency: "direct main" description: @@ -337,7 +342,7 @@ packages: source: hosted version: "4.7.2" intl: - dependency: transitive + dependency: "direct main" description: name: intl sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" diff --git a/pubspec.yaml b/pubspec.yaml index a7db1bb..5fb4b53 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,9 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter + intl: any # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. @@ -68,6 +71,7 @@ dev_dependencies: # The following section is specific to Flutter packages. flutter: + generate: true # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in diff --git a/tools/translate.py b/tools/translate.py new file mode 100644 index 0000000..54dd3bc --- /dev/null +++ b/tools/translate.py @@ -0,0 +1,723 @@ +#!/usr/bin/env python3 +""" +translate_arb_with_ollama.py + +Translates ARB/JSON localization values using a local Ollama model, while: +- preserving keys +- skipping "@@locale" and all "@key" metadata blocks +- preserving placeholders like {deviceName}, {count, plural, ...} +- writing a new file with updated @@locale +- printing progress as it runs + +Usage: + python translate_arb_with_ollama.py \ + --in /home/zjs81/Desktop/meshcore-open/lib/l10n/app_en.arb \ + --out /home/zjs81/Desktop/meshcore-open/lib/l10n/app_es.arb \ + --to-locale es \ + --model ministral-3:latest \ + --temperature 0 \ + --concurrency 4 +""" + +from __future__ import annotations + +import argparse +import json +import re +import sys +import time +from concurrent.futures import ThreadPoolExecutor, as_completed +from dataclasses import dataclass +from typing import Any, Dict, List, Tuple, Optional +from urllib import request + + +# Simple placeholder like {name}, {count}, {deviceName} +SIMPLE_PLACEHOLDER_RE = re.compile(r"\{(\w+)\}") +# ICU plural/select variable name extraction: {count, plural, ...} or {gender, select, ...} +ICU_VAR_RE = re.compile(r"\{(\w+)\s*,\s*(?:plural|select|selectordinal)\s*,", re.IGNORECASE) + + +@dataclass +class OllamaConfig: + host: str + model: str + timeout_s: float + temperature: float + num_ctx: int + num_predict: int + top_p: float + + +def http_post_json(url: str, payload: Dict[str, Any], timeout_s: float) -> Dict[str, Any]: + data = json.dumps(payload).encode("utf-8") + req = request.Request( + url, + data=data, + headers={"Content-Type": "application/json"}, + method="POST", + ) + with request.urlopen(req, timeout=timeout_s) as resp: + body = resp.read().decode("utf-8") + return json.loads(body) + + +def strip_markdown(s: str) -> str: + """Remove common markdown formatting from output.""" + # Remove bold/italic markers + s = re.sub(r'\*\*(.+?)\*\*', r'\1', s) + s = re.sub(r'\*(.+?)\*', r'\1', s) + s = re.sub(r'__(.+?)__', r'\1', s) + s = re.sub(r'_(.+?)_', r'\1', s) + # Remove stray asterisks + s = re.sub(r'\*+', '', s) + return s.strip() + + +def ollama_generate(cfg: OllamaConfig, prompt: str) -> str: + url = cfg.host.rstrip("/") + "/api/generate" + payload = { + "model": cfg.model, + "prompt": prompt, + "stream": False, + "options": { + "temperature": cfg.temperature, + "num_ctx": cfg.num_ctx, + "num_predict": cfg.num_predict, + "top_p": cfg.top_p, + }, + } + resp = http_post_json(url, payload, cfg.timeout_s) + out = resp.get("response", "") + # Clean up common LLM artifacts + out = strip_markdown(out) + return out.strip() + + +def extract_placeholder_names(s: str) -> List[str]: + """Extract placeholder variable names (not the full braced expression). + + For '{name}' returns ['name'] + For '{count} {count, plural, =1{hop} other{hops}}' returns ['count'] + """ + names = set() + # Get ICU variable names first + for m in ICU_VAR_RE.finditer(s): + names.add(m.group(1)) + # Get simple placeholders, but skip if they're inside ICU blocks (text forms like {hop}) + # We do this by checking if the name is also an ICU variable - if not, it's a simple placeholder + # unless it looks like a word (ICU text forms are usually short words) + for m in SIMPLE_PLACEHOLDER_RE.finditer(s): + name = m.group(1) + # Check if this appears as a simple {name} placeholder (not inside ICU) + # by looking at what comes after it + full_match = m.group(0) + pos = m.start() + # Look for pattern like {name, plural/select - if found, skip (handled by ICU_VAR_RE) + rest = s[pos:] + if re.match(r"\{\w+\s*,\s*(?:plural|select|selectordinal)", rest, re.IGNORECASE): + continue + # Check if this is likely a text form inside ICU (preceded by =X{ or other{) + before = s[:pos] + if re.search(r"(?:=\d+|zero|one|two|few|many|other)\s*$", before, re.IGNORECASE): + continue # This is a text form like "=1{hop}", skip it + names.add(name) + return sorted(names) + + +def build_prompt(text: str, target_lang: str, placeholder_names: List[str], has_icu: bool, ask_confidence: bool = False) -> str: + preserve_list = "\n".join(f"- {{{t}}}" for t in placeholder_names) if placeholder_names else "- (none)" + + icu_note = "" + if has_icu: + icu_note = ( + "ICU FORMAT RULES:\n" + f"- This text uses ICU plural/select format: {{var, plural, =1{{singular}} other{{plural}}}}\n" + "- Keep structure keywords EXACTLY: plural, select, =0, =1, =2, zero, one, two, few, many, other\n" + f"- TRANSLATE the words inside each form to {target_lang}\n" + "- Example: =1{item} other{items} -> translate 'item'/'items' but keep =1{{ }} other{{ }} structure\n\n" + ) + + if ask_confidence: + return ( + f"Translate this UI string to {target_lang}.\n\n" + "RULES:\n" + "- Placeholders like {name}, {count} must appear EXACTLY unchanged.\n" + "- Use infinitive verb forms for buttons (Save, Delete, etc.).\n" + f"- Use natural {target_lang} word order.\n" + "- Keep brand names and technical terms unchanged.\n\n" + f"{icu_note}" + f"Placeholders: {', '.join(f'{{{t}}}' for t in placeholder_names) if placeholder_names else 'none'}\n\n" + f"English: {text}\n\n" + "Respond with EXACTLY two lines:\n" + "1. The translation (no quotes)\n" + "2. Confidence score 1-5 (5=certain, 1=unsure)\n\n" + "Example response:\n" + "Guardar archivo\n" + "5" + ) + else: + return ( + f"Translate this UI string to {target_lang}. Return ONLY the translation.\n\n" + "RULES:\n" + "- Output the translated text ONLY. No markdown, no quotes, no explanations.\n" + "- Placeholders like {name}, {count} must appear EXACTLY unchanged.\n" + "- Use infinitive verb forms for buttons (Save, Delete, etc.).\n" + f"- Use natural {target_lang} word order.\n" + "- Keep brand names and technical terms unchanged.\n" + "- Translation length should be similar to the original.\n\n" + f"{icu_note}" + f"Placeholders: {', '.join(f'{{{t}}}' for t in placeholder_names) if placeholder_names else 'none'}\n\n" + f"English: {text}\n" + f"{target_lang}:" + ) + + +def parse_confidence_response(response: str) -> Tuple[str, int]: + """Parse response with translation and confidence score. + + Returns (translation, confidence) where confidence is 1-5, or 0 if unparseable. + """ + lines = response.strip().split('\n') + if len(lines) >= 2: + translation = '\n'.join(lines[:-1]).strip() # All but last line + try: + # Try to extract number from last line + last_line = lines[-1].strip() + # Handle formats like "5", "5/5", "Confidence: 5" + match = re.search(r'\b([1-5])\b', last_line) + if match: + confidence = int(match.group(1)) + return translation, confidence + except ValueError: + pass + # Fallback: treat whole response as translation with unknown confidence + return strip_markdown(response), 0 + + +def looks_like_translation_failed(src: str, out: str) -> bool: + if not out: + return True + if src.strip() == out.strip() and len(src.strip()) > 8: + return True + # Detect hallucination: output much longer than input (3x+ for short strings, 2x for longer) + src_len = len(src.strip()) + out_len = len(out.strip()) + if src_len < 50 and out_len > src_len * 3: + return True + if src_len >= 50 and out_len > src_len * 2: + return True + return False + + +def has_icu_block(s: str) -> bool: + """Check if string contains ICU plural/select block.""" + return bool(ICU_VAR_RE.search(s)) + + +def validate_preserved_tokens(src: str, out: str) -> Tuple[bool, Optional[str]]: + """Validate that placeholder names are preserved in translation.""" + src_names = extract_placeholder_names(src) + + # Check each placeholder name appears in output + for name in src_names: + # Look for {name} or {name, plural/select...} + pattern = r"\{" + re.escape(name) + r"(?:\}|\s*,)" + if not re.search(pattern, out): + return False, f"Missing placeholder: {{{name}}}" + + # If source has ICU block, output should too + if has_icu_block(src) and not has_icu_block(out): + return False, "ICU plural/select block missing in output" + + return True, None + + +def compute_confidence(src: str, out: str) -> Tuple[float, List[str]]: + """ + Compute confidence score (0.0 to 1.0) for a translation. + Returns (score, list of issues). + """ + issues = [] + score = 1.0 + + src_len = len(src.strip()) + out_len = len(out.strip()) + + # Length ratio check + if src_len > 0: + ratio = out_len / src_len + if ratio < 0.3: # Way too short + score -= 0.4 + issues.append("too_short") + elif ratio < 0.5: + score -= 0.2 + issues.append("short") + elif ratio > 2.5: # Way too long + score -= 0.4 + issues.append("too_long") + elif ratio > 1.8: + score -= 0.2 + issues.append("long") + + # Contains question mark when source doesn't (model asking questions) + if '?' in out and '?' not in src: + score -= 0.3 + issues.append("added_question") + + # Contains common LLM artifacts + artifacts = ['```', '**', 'translation:', 'here is', 'certainly', 'i can', 'i\'ll'] + out_lower = out.lower() + for artifact in artifacts: + if artifact in out_lower: + score -= 0.3 + issues.append(f"artifact:{artifact}") + break + + # Output looks like it's in English still (common words) + english_indicators = ['the ', ' is ', ' are ', ' was ', ' were ', ' have ', ' has ', 'you ', ' your '] + english_count = sum(1 for ind in english_indicators if ind in out_lower) + if english_count >= 3 and src_len > 20: + score -= 0.3 + issues.append("likely_english") + + # Contains newlines when source doesn't + if '\n' in out and '\n' not in src: + score -= 0.2 + issues.append("added_newlines") + + # ICU/placeholder validation + ok, _ = validate_preserved_tokens(src, out) + if not ok: + score -= 0.3 + issues.append("placeholder_error") + + return max(0.0, score), issues + + +# Keys to skip translation (brand names) +SKIP_KEYS = { + "appTitle", +} + +# Manual translations for problematic strings (key -> {locale: translation}) +MANUAL_TRANSLATIONS: Dict[str, Dict[str, str]] = { + "repeater_daysHoursMinsSecs": { + "es": "{days} días {hours}h {minutes}m {seconds}s", + "fr": "{days} jours {hours}h {minutes}m {seconds}s", + "de": "{days} Tage {hours}h {minutes}m {seconds}s", + "it": "{days} giorni {hours}h {minutes}m {seconds}s", + "pt": "{days} dias {hours}h {minutes}m {seconds}s", + "pl": "{days} dni {hours}h {minutes}m {seconds}s", + "sk": "{days} dní {hours}h {minutes}m {seconds}s", + "sl": "{days} dni {hours}h {minutes}m {seconds}s", + "cs": "{days} dní {hours}h {minutes}m {seconds}s", + "ja": "{days}日 {hours}時間 {minutes}分 {seconds}秒", + "ko": "{days}일 {hours}시간 {minutes}분 {seconds}초", + "zh": "{days}天 {hours}小时 {minutes}分 {seconds}秒", + "ru": "{days} дней {hours}ч {minutes}м {seconds}с", + "bg": "{days} дни {hours}ч {minutes}м {seconds}с", + "nl": "{days} dagen {hours}u {minutes}m {seconds}s", + "sv": "{days} dagar {hours}t {minutes}m {seconds}s", + }, +} + + +def is_translatable_entry(key: str, value: Any) -> bool: + if key == "@@locale": + return False + if key in SKIP_KEYS: + return False + if key.startswith("@"): + return False + if not isinstance(value, str): + return False + if value.strip() == "": + return False + return True + + +def translate_one( + key: str, + text: str, + target_lang: str, + cfg: OllamaConfig, + retries: int, + backoff_s: float, + fallback_cfg: Optional[OllamaConfig] = None, + confidence_threshold: float = 0.7, + model_confidence_threshold: int = 4, + ask_model_confidence: bool = True, +) -> Tuple[str, str, Optional[str], bool]: + """ + Translate a single string. + Returns (key, translated_text, error_or_none, used_fallback_model). + """ + placeholder_names = extract_placeholder_names(text) + text_has_icu = has_icu_block(text) + + # Ask for confidence if we have a fallback model + should_ask_confidence = ask_model_confidence and fallback_cfg and fallback_cfg.model != cfg.model + prompt = build_prompt(text, target_lang, placeholder_names, text_has_icu, ask_confidence=should_ask_confidence) + used_fallback = False + + last_err: Optional[str] = None + for attempt in range(retries + 1): + try: + raw_out = ollama_generate(cfg, prompt) + + # Parse confidence if we asked for it + if should_ask_confidence: + out, model_confidence = parse_confidence_response(raw_out) + else: + out = raw_out + model_confidence = 5 # Assume high confidence if not asked + + ok, why = validate_preserved_tokens(text, out) + if not ok: + last_err = f"Validation failed: {why}" + # Retry without confidence format for simpler response + prompt = build_prompt(text, target_lang, placeholder_names, text_has_icu, ask_confidence=False) + prompt = ( + prompt + + "\n\nIMPORTANT: You MUST keep every {...} segment exactly unchanged. " + "If you cannot, return the original text unchanged." + ) + raise ValueError(last_err) + + if looks_like_translation_failed(text, out) and attempt < retries: + last_err = "Output identical/suspicious; retrying" + time.sleep(backoff_s * (attempt + 1)) + continue + + # Check if model reported low confidence - use fallback + if model_confidence > 0 and model_confidence < model_confidence_threshold and fallback_cfg: + fallback_prompt = build_prompt(text, target_lang, placeholder_names, text_has_icu, ask_confidence=False) + fallback_out = ollama_generate(fallback_cfg, fallback_prompt) + fallback_ok, _ = validate_preserved_tokens(text, fallback_out) + if fallback_ok and not looks_like_translation_failed(text, fallback_out): + return key, fallback_out, None, True + + # Also check computed confidence and use fallback model if needed + confidence, issues = compute_confidence(text, out) + if confidence < confidence_threshold and fallback_cfg and fallback_cfg.model != cfg.model: + # Low confidence - try with bigger model + fallback_prompt = build_prompt(text, target_lang, placeholder_names, text_has_icu) + fallback_out = ollama_generate(fallback_cfg, fallback_prompt) + fallback_ok, _ = validate_preserved_tokens(text, fallback_out) + fallback_conf, _ = compute_confidence(text, fallback_out) + + if fallback_ok and fallback_conf > confidence: + # Fallback is better + return key, fallback_out, None, True + elif fallback_ok and not ok: + # Original failed validation but fallback passed + return key, fallback_out, None, True + + return key, out, None, used_fallback + + except Exception as e: + last_err = str(e) + if attempt < retries: + time.sleep(backoff_s * (attempt + 1)) + continue + + # Last resort: try fallback model + if fallback_cfg and fallback_cfg.model != cfg.model: + try: + fallback_prompt = build_prompt(text, target_lang, placeholder_names, text_has_icu) + fallback_out = ollama_generate(fallback_cfg, fallback_prompt) + fallback_ok, _ = validate_preserved_tokens(text, fallback_out) + if fallback_ok and not looks_like_translation_failed(text, fallback_out): + return key, fallback_out, None, True + except Exception: + pass + + return key, text, last_err, False # fallback to original on failure + + +def fmt_duration(seconds: float) -> str: + if seconds < 60: + return f"{seconds:.1f}s" + m = int(seconds // 60) + s = seconds - 60 * m + if m < 60: + return f"{m}m {s:.0f}s" + h = m // 60 + m2 = m % 60 + return f"{h}h {m2}m" + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("--in", dest="in_path", required=True, help="Input .arb/.json file path") + ap.add_argument("--out", dest="out_path", required=True, help="Output .arb/.json file path") + ap.add_argument("--to-locale", required=True, help="Target locale code, e.g. es, fr, de") + ap.add_argument("--target-lang", default=None, help="Target language name for the model, e.g. Spanish (defaults from locale)") + ap.add_argument("--model", default="gemma3:4b", help="Ollama model name") + ap.add_argument("--fallback-model", default=None, help="Larger model to use for low-confidence translations") + ap.add_argument("--confidence-threshold", type=float, default=0.7, help="Computed confidence threshold to trigger fallback (0.0-1.0)") + ap.add_argument("--model-confidence-threshold", type=int, default=4, help="Model self-reported confidence threshold (1-5, use fallback if below)") + ap.add_argument("--retry-model", default="ministral-3:latest", help="Model to use for end-of-run retries") + ap.add_argument("--host", default="http://localhost:11434", help="Ollama host") + ap.add_argument("--timeout", type=float, default=120.0, help="HTTP timeout seconds") + ap.add_argument("--temperature", type=float, default=0.2, help="Model temperature") + ap.add_argument("--num-ctx", type=int, default=4096, help="Context size") + ap.add_argument("--num-predict", type=int, default=256, help="Max tokens to generate") + ap.add_argument("--top-p", type=float, default=0.9, help="Top-p") + ap.add_argument("--concurrency", type=int, default=4, help="Parallel requests") + ap.add_argument("--retries", type=int, default=2, help="Retries per string") + ap.add_argument("--backoff", type=float, default=0.6, help="Backoff seconds base") + ap.add_argument("--dry-run", action="store_true", help="Do not write file; just print summary") + ap.add_argument("--progress-every", type=int, default=1, help="Print progress every N completed strings (default: 1)") + args = ap.parse_args() + + locale_map = { + "es": "Spanish", + "fr": "French", + "de": "German", + "it": "Italian", + "pt": "Portuguese", + "pt-BR": "Brazilian Portuguese", + "ja": "Japanese", + "ko": "Korean", + "zh": "Chinese (Simplified)", + "zh-Hant": "Chinese (Traditional)", + "ru": "Russian", + "uk": "Ukrainian", + "ar": "Arabic", + "hi": "Hindi", + "tr": "Turkish", + "nl": "Dutch", + "sv": "Swedish", + "no": "Norwegian", + "da": "Danish", + "fi": "Finnish", + "pl": "Polish", + "cs": "Czech", + "sk": "Slovak", + "sl": "Slovenian", + "bg": "Bulgarian", + "el": "Greek", + "he": "Hebrew", + "th": "Thai", + "vi": "Vietnamese", + "id": "Indonesian", + } + target_lang = args.target_lang or locale_map.get(args.to_locale, args.to_locale) + + try: + with open(args.in_path, "r", encoding="utf-8") as f: + data = json.load(f) + except Exception as e: + print(f"Failed to read input: {e}", file=sys.stderr) + return 2 + + if not isinstance(data, dict): + print("Input JSON must be an object at top-level.", file=sys.stderr) + return 2 + + cfg = OllamaConfig( + host=args.host, + model=args.model, + timeout_s=args.timeout, + temperature=args.temperature, + num_ctx=args.num_ctx, + num_predict=args.num_predict, + top_p=args.top_p, + ) + + # Fallback model for low-confidence translations + fallback_cfg = None + if args.fallback_model: + fallback_cfg = OllamaConfig( + host=args.host, + model=args.fallback_model, + timeout_s=args.timeout, + temperature=args.temperature, + num_ctx=args.num_ctx, + num_predict=args.num_predict, + top_p=args.top_p, + ) + + out_data: Dict[str, Any] = dict(data) + out_data["@@locale"] = args.to_locale + + items: List[Tuple[str, str]] = [(k, v) for k, v in data.items() if is_translatable_entry(k, v)] + + # Apply manual translations first + manual_count = 0 + items_to_translate: List[Tuple[str, str]] = [] + for k, v in items: + if k in MANUAL_TRANSLATIONS and args.to_locale in MANUAL_TRANSLATIONS[k]: + out_data[k] = MANUAL_TRANSLATIONS[k][args.to_locale] + manual_count += 1 + else: + items_to_translate.append((k, v)) + + if manual_count > 0: + print(f"Applied {manual_count} manual translation(s)") + + total = len(items_to_translate) + if total == 0 and manual_count == 0: + print("No translatable string entries found (excluding @@locale and @metadata).", file=sys.stderr) + return 1 + + if total == 0: + print("All strings handled by manual translations.") + else: + fallback_info = f" (fallback: {args.fallback_model})" if args.fallback_model else "" + print(f"Translating {total} strings -> {target_lang} using {cfg.model}{fallback_info} (concurrency={args.concurrency})") + + start = time.time() + + failures: List[Tuple[str, str]] = [] + translated_ok = manual_count # Count manual translations as OK + fallback_used = 0 + completed = 0 + + # Build a lookup for original text by key + items_dict: Dict[str, str] = dict(items_to_translate) + + # Submit all tasks up front + if total > 0: + with ThreadPoolExecutor(max_workers=max(1, args.concurrency)) as ex: + future_to_key = { + ex.submit( + translate_one, + key=k, + text=v, + target_lang=target_lang, + cfg=cfg, + retries=args.retries, + backoff_s=args.backoff, + fallback_cfg=fallback_cfg, + confidence_threshold=args.confidence_threshold, + model_confidence_threshold=args.model_confidence_threshold, + ask_model_confidence=bool(args.fallback_model), + ): k + for (k, v) in items_to_translate + } + + for fut in as_completed(future_to_key): + k, translated, err, used_fallback = fut.result() + out_data[k] = translated + + completed += 1 + if err: + failures.append((k, err)) + status = "FAIL" + else: + translated_ok += 1 + if used_fallback: + fallback_used += 1 + status = "OK*" # asterisk indicates fallback model was used + else: + status = "OK" + + if args.progress_every > 0 and (completed % args.progress_every == 0 or completed == total): + elapsed = time.time() - start + rate = completed / elapsed if elapsed > 0 else 0.0 + remaining = (total - completed) / rate if rate > 0 else 0.0 + # Keep it single-line friendly but readable. + print( + f"[{completed:>4}/{total}] {status:<4} {k} | " + f"elapsed {fmt_duration(elapsed)} | ETA {fmt_duration(remaining)}" + ) + + elapsed = time.time() - start + fallback_msg = f", used_fallback_model={fallback_used}" if fallback_used > 0 else "" + print(f"Done in {fmt_duration(elapsed)}. OK={translated_ok}{fallback_msg}, errors={len(failures)}") + + # Retry failed translations at the end with increasing temperature + retry_round = 1 + max_end_retries = 3 + retry_model = args.retry_model + while failures and retry_round <= max_end_retries: + # Increase temperature for each retry round + retry_temp = min(cfg.temperature + (0.2 * retry_round), 1.0) + print(f"\n--- Retry round {retry_round}/{max_end_retries} for {len(failures)} failed key(s) (model={retry_model}, temp={retry_temp:.1f}) ---") + retry_items = [(k, items_dict[k]) for k, _ in failures] + failures = [] + retry_completed = 0 + retry_total = len(retry_items) + retry_start = time.time() + + # Create config with higher temperature (and optionally different model) for retries + retry_cfg = OllamaConfig( + host=cfg.host, + model=retry_model, + timeout_s=cfg.timeout_s, + temperature=retry_temp, + num_ctx=cfg.num_ctx, + num_predict=cfg.num_predict, + top_p=cfg.top_p, + ) + + with ThreadPoolExecutor(max_workers=max(1, args.concurrency)) as ex: + future_to_key = { + ex.submit( + translate_one, + key=k, + text=v, + target_lang=target_lang, + cfg=retry_cfg, + retries=args.retries, + backoff_s=args.backoff, + ): k + for (k, v) in retry_items + } + + for fut in as_completed(future_to_key): + k, translated, err, used_fb = fut.result() + out_data[k] = translated + + retry_completed += 1 + if err: + failures.append((k, err)) + status = "FAIL" + else: + translated_ok += 1 + status = "OK" + + if args.progress_every > 0 and (retry_completed % args.progress_every == 0 or retry_completed == retry_total): + elapsed = time.time() - retry_start + rate = retry_completed / elapsed if elapsed > 0 else 0.0 + remaining = (retry_total - retry_completed) / rate if rate > 0 else 0.0 + print( + f"[{retry_completed:>4}/{retry_total}] {status:<4} {k} | " + f"elapsed {fmt_duration(elapsed)} | ETA {fmt_duration(remaining)}" + ) + + retry_elapsed = time.time() - retry_start + print(f"Retry round {retry_round} done in {fmt_duration(retry_elapsed)}. Remaining failures: {len(failures)}") + retry_round += 1 + + total_elapsed = time.time() - start + print(f"\nTotal time: {fmt_duration(total_elapsed)}. OK={translated_ok}, final fallback={len(failures)}") + + if failures: + print("Fallback keys (kept original English due to errors):") + for k, err in failures[:60]: + print(f" - {k}: {err}") + if len(failures) > 60: + print(f" ... and {len(failures) - 60} more") + + if args.dry_run: + print("Dry run: not writing output file.") + return 0 + + try: + with open(args.out_path, "w", encoding="utf-8") as f: + json.dump(out_data, f, ensure_ascii=False, indent=2) + f.write("\n") + except Exception as e: + print(f"Failed to write output: {e}", file=sys.stderr) + return 2 + + print(f"Wrote: {args.out_path}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())