mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 05:26:47 +00:00
394201cd32
* chore: bump version to 4.1.0 [skip ci] * fix(collections): stop findDuplicateCollectionPlace merging places by coordinates alone Three places answered "is this a place the trip already has?", not two: PlacesService.findDuplicatePlace and isPlaceDuplicate got the shared strategy list in #2130; CollectionsService.findDuplicateCollectionPlace was missed and kept its own hand-rolled copy of the pre-#2130 order. Unlike findDuplicatePlace, this one had no isPlaceDuplicate() guard in front of it — savePlace calls it directly — so the coordinate fallback for a NAMED candidate was live, not latent: two distinct places sharing an address (a restaurant and the bar upstairs) would report each other as duplicates the moment their coordinates round to the same ~11 m box, regardless of name. It also never read google_place_id/google_ftid/osm_id at all, even though every collection_places row stores them, so a place renamed since it was saved could be saved again instead of being recognised by its provider id. Now walks placeMatchStrategies() from @trek/shared, same as findMatchingPlaceId: provider id, then name, then coordinates only when there is no name. savePlace passes the provider id fields through since they are already on the request body; the two bulk call sites (importablePlaces, saveFromTripPlaces) are unchanged, since their source rows don't carry provider ids to pass. Closes #2137 * fix(collections): ask the same question at all three call sites savePlace was not the only caller of findDuplicateCollectionPlace. The bulk copy already carries google_place_id/google_ftid/osm_id into the row it writes but asked without them, and the import picker never selected them at all, so a renamed place was recognised on one path and not on the other two. The picker answering differently from the import is the drift the method exists to prevent: a row shown as new would come back refused. COLLECTIONS-SVC-102 and -103 cover the bulk copy and the picker. * fix(map): give the Leaflet map its own zoom ceiling, so a vector basemap cannot take the planner down Opening a trip on 4.1.0 could land on the error boundary with "Map has no maxZoom specified", and so could the map settings tab, which left no screen from which to pick a different basemap. Leaflet answers getMaxZoom() from the map options first and otherwise from a layer that brought one, and only a GridLayer ever contributes via its beforeAdd hook. A vector basemap is a GL canvas on a plain L.Layer, so it contributes nothing, and MapContainer set no ceiling of its own. MarkerClusterGroup.onAdd refuses an infinite one by throwing, before any clustering, so an empty trip hit it too. That path opened when the default basemap became a MapLibre style. It reaches further than an operator choosing OpenFreeMap: resolveTileUrl sends a keyless CARTO template to the app default, which is now a vector style, so every instance still carrying the old CARTO basemap fell into it on upgrade. The ceiling belongs on the map rather than on the base layer, because it has to hold whichever of the three branches renders. 19 matches what the raster and satellite layers already carried, so nothing changes for the maps that worked. SharedTripPage gets the same treatment: it has no cluster to throw, but it draws the same vector basemap and its fitBounds asks for a ceiling. mapZoomCeiling.test.ts pins Leaflet's own semantics against the real library rather than a mock, since a mocked react-leaflet would have kept passing through all of this. * fix(map): put the CARTO key back on the template the settings preview draws The map settings fields hold what the user is editing rather than what useTileUrl already resolved, so the preview received a bare template with no key on it. resolveTileUrl then read it as a keyless CARTO url and did what it is meant to do with one: fall back to the app default. The preview drew OpenFreeMap while the fields said CARTO, whether or not a key was saved. Same reason the tab crashed for anyone on a CARTO basemap even after entering a key, which is the loop that made this hard to escape: the key is entered on the page the fallback had taken down. FE-COMP-MAP-033b pins the template the preview is handed, with and without a key. * fix(admin): put the CARTO key back on the default-settings map preview too Same shape as the user-facing map tab, and reported alongside it: the field holds what the admin is editing, so the preview resolved a keyless CARTO template and drew the app default instead of the basemap being set. * fix(mobile): put the CARTO key back on the phone map settings preview too The third preview with the same shape, and the one that matters most while the crash is live: the phone layout is where someone would go to change the basemap when the desktop tab will not open. * fix(calendar): a fully timed stay is its two hand-overs, not a week-long bar Closes #2136 A stay was always exported as an all-day block across its whole range, and the check-in and check-out markers came on top of it. When the stay records both ends of its clock the markers already say everything the block does, and the block is the half nobody can act on: it takes a week of calendar to repeat what two one-hour events state precisely. Same shape as the parking and rental windows in #2068. Only where the markers actually stand in for the booking, though. They are emitted once per stay and titled from its lowest-id reservation, so a second room on the same stay would otherwise be left with nothing at all. A stay that knows only one end keeps its block too, since nothing else carries the other end's date. CAL-025b covers the drop, -025c the one-sided stay, -025d the second room. * fix(mobile): the phone admin map preview needs the CARTO key too The fourth preview with the same shape, missed when the other three were fixed. Sonar pointed at it: the desktop and phone admin pages are near-identical, so the duplication report named the file the change had not reached. * chore: bump version to 4.1.1 [skip ci] * feat(plugins): admin editor for instance-wide plugin settings The scope:'instance' settings a plugin declares had API endpoints but no UI. - shared: plugins.schema.ts — the settings-field descriptor and the admin instance-config GET/PUT wire contracts, imported by both sides - server: GET /api/admin/plugins/:id/config now returns the declared fields alongside the (masked) values; PUT re-spawns an ACTIVE plugin (its child reads config once, at init) and reports it via 'restarted'; the admin list carries instanceSettingsCount so the UI gates its menu item without a fetch - client: 'Instance settings' row action opening a form modal (desktop) / MSheet (phone) in both admin shells — checkbox/select/secret rendering as in the user settings form; an untouched secret mask is never sent back - i18n: three new admin.plugins.* keys in every locale * refactor(plugins): move the admin body contracts to @trek/shared The remaining plugin DTO schemas (install, link, activate, uninstall, retrust, update, egress-hosts, user-settings update, route) now live in shared/src/plugins/plugins.schema.ts with their inferred types, alongside the instance-config contracts. The journey-contract doctrine notes (#1842) moved with them — each body stays deliberately loose so the handlers keep the rejections and fallbacks they already own, and new spec tests pin that looseness so a well-meant tightening breaks a test that explains itself. plugins.dto.ts is now thin createZodDto wrappers over the shared schemas (same class names, no controller changes), and the client's pluginInstall types its options and body against PluginInstallRequest. * fix(admin): offer Allowed hosts only to plugins that declared operatorEgress The row's egress chip was already gated on the declaration, but the kebab menu (desktop) and row action sheet (phone) offered Allowed hosts on every installed plugin — inviting the admin to widen egress for plugins that never asked for it. Both entries now render only when the plugin declares operatorEgress; the dialog's unsupported-notice fallback stays as the truth-teller for stale list data. * test(admin): close the Sonar gaps on the instance-settings form The PR gate flagged new-code coverage (76.4%) and duplication (10.9%). - The two identical 39-line handler blocks were logic, not markup — they move into one shared useInstanceSettings hook; each shell keeps its own markup (the deliberate desktop/phone divergence stays) - New tests per shell cover the untested branches: every field type renders and round-trips into the save payload (select, checkbox/MToggle, number, hint, no-label key fallback), a failed fetch is a toast, a rejected save shows the server reason and keeps the edits, and the dialog/sheet closes without saving - INS-009 covers the controller's no-body '|| {}' fallback --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: michael-bohr <263459669+michael-bohr@users.noreply.github.com> Co-authored-by: Maurice <mauriceboe@icloud.com>
715 lines
69 KiB
TypeScript
715 lines
69 KiB
TypeScript
import type { TranslationStrings } from '../types';
|
||
|
||
const admin: TranslationStrings = {
|
||
'admin.notifications.title': 'n',
|
||
'admin.notifications.hint': 'Виберіть канал сповіщень. Одночасно може бути активним лише один.',
|
||
'admin.notifications.none': 'Вимкнено',
|
||
'admin.notifications.email': 'Ел. пошта (SMTP)',
|
||
'admin.notifications.webhook': 'Webhook',
|
||
'admin.notifications.save': 'Зберегти налаштування сповіщень',
|
||
'admin.notifications.saved': 'Налаштування сповіщень збережені',
|
||
'admin.notifications.testWebhook': 'Відправити тестовий webhook',
|
||
'admin.notifications.testWebhookSuccess': 'Тестовий webhook успішно відправлено',
|
||
'admin.notifications.testWebhookFailed': "Помилка відправки тестового webhook'а",
|
||
'admin.smtp.title': 'Пошта та сповіщення',
|
||
'admin.smtp.hint': 'Налаштування SMTP для відправки сповіщень електронною поштою.',
|
||
'admin.smtp.testButton': 'Відправити тестовий лист',
|
||
'admin.webhook.hint': 'Відправляти сповіщення через зовнішній webhook (Discord, Slack тощо).',
|
||
'admin.smtp.testSuccess': 'Тестовий лист успішно відправлено',
|
||
'admin.smtp.testFailed': 'Помилка відправки тестового листа',
|
||
'admin.title': 'Адміністрування',
|
||
'admin.subtitle': 'Управління користувачами та системні налаштування',
|
||
'admin.tabs.users': 'Користувачі',
|
||
'admin.tabs.categories': 'Категорії',
|
||
'admin.tabs.backup': 'Резервна копія',
|
||
'admin.tabs.audit': 'Аудит',
|
||
'admin.stats.users': 'Користувачі',
|
||
'admin.stats.trips': 'Подорожі',
|
||
'admin.stats.places': 'Місця',
|
||
'admin.stats.photos': 'Фото',
|
||
'admin.stats.files': 'Файли',
|
||
'admin.table.user': 'Користувач',
|
||
'admin.table.email': 'Ел. пошта',
|
||
'admin.table.role': 'Роль',
|
||
'admin.table.created': 'Створено',
|
||
'admin.table.lastLogin': 'Останній вхід',
|
||
'admin.table.actions': 'Дії',
|
||
'admin.you': '(Ви)',
|
||
'admin.editUser': 'Редагувати користувача',
|
||
'admin.newPassword': 'Новий пароль',
|
||
'admin.newPasswordHint': 'Залиште порожнім, щоб зберегти поточний пароль',
|
||
'admin.deleteUser': 'Видалити користувача «{name}»? Усі подорожі будуть безповоротно видалені.',
|
||
'admin.deleteUserTitle': 'Видалити користувача',
|
||
'admin.newPasswordPlaceholder': 'Введіть новий пароль…',
|
||
'admin.toast.loadError': 'Не вдалося завантажити дані адміністрування',
|
||
'admin.toast.userUpdated': 'Користувача оновлено',
|
||
'admin.toast.updateError': 'Помилка оновлення',
|
||
'admin.toast.userDeleted': 'Користувача видалено',
|
||
'admin.toast.deleteError': 'Помилка видалення',
|
||
'admin.toast.cannotDeleteSelf': 'Неможливо видалити власний акаунт',
|
||
'admin.toast.userCreated': 'Користувача створено',
|
||
'admin.toast.createError': 'Помилка створення користувача',
|
||
'admin.toast.fieldsRequired': 'Ім’я користувача, ел. пошта та пароль обов’язкові',
|
||
'admin.createUser': 'Створити користувача',
|
||
'admin.invite.title': 'Запрошення за посиланням',
|
||
'admin.invite.subtitle': 'Створення одноразових посилань для реєстрації',
|
||
'admin.invite.create': 'Створити посилання',
|
||
'admin.invite.createAndCopy': 'Створити та скопіювати',
|
||
'admin.invite.empty': 'Посилання-запрошення ще не створені',
|
||
'admin.invite.maxUses': 'Макс. використань',
|
||
'admin.invite.expiry': 'Дійсне',
|
||
'admin.invite.uses': 'використано',
|
||
'admin.invite.expiresAt': 'закінчується',
|
||
'admin.invite.createdBy': 'від',
|
||
'admin.invite.active': 'Активне',
|
||
'admin.invite.expired': 'Закінчилося',
|
||
'admin.invite.usedUp': 'Вичерпано',
|
||
'admin.invite.copied': 'Посилання-запрошення скопійовано',
|
||
'admin.invite.copyLink': 'Скопіювати посилання',
|
||
'admin.invite.deleted': 'Посилання-запрошення видалено',
|
||
'admin.invite.createError': 'Помилка створення посилання',
|
||
'admin.invite.deleteError': 'Помилка видалення посилання',
|
||
'admin.tabs.settings': 'Налаштування',
|
||
'admin.allowRegistration': 'Дозволити реєстрацію',
|
||
'admin.allowRegistrationHint': 'Нові користувачі можуть реєструватися самостійно',
|
||
'admin.authMethods': 'Методи автентифікації',
|
||
'admin.passwordLogin': 'Вхід за паролем',
|
||
'admin.passwordLoginHint': 'Дозволити користувачам входити за ел. поштою та паролем',
|
||
'admin.passwordRegistration': 'Реєстрація за паролем',
|
||
'admin.passwordRegistrationHint': 'Дозволити новим користувачам реєструватися за ел. поштою та паролем',
|
||
'admin.oidcLogin': 'Вхід через SSO',
|
||
'admin.oidcLoginHint': 'Дозволити користувачам входити через SSO',
|
||
'admin.oidcRegistration': 'Автоматичне створення SSO-акаунтів',
|
||
'admin.oidcRegistrationHint': 'Автоматично створювати акаунти для нових SSO-користувачів',
|
||
'admin.envOverrideHint':
|
||
'Налаштування входу за паролем контролюються змінною середовища OIDC_ONLY і не можуть бути змінені тут.',
|
||
'admin.lockoutWarning': 'Потрібно залишити увімкненим принаймні один метод входу',
|
||
'admin.requireMfa': 'Вимагати двофакторну автентифікацію (2FA)',
|
||
'admin.requireMfaHint':
|
||
'Користувачі без 2FA повинні завершити налаштування в розділі «Налаштування» перед використанням програми.',
|
||
'admin.apiKeys': 'API-ключі',
|
||
'admin.apiKeysHint': 'Необов’язково. Включає розширені дані про місця, такі як фото та погода.',
|
||
'admin.mapsKey': 'API-ключ Google Maps',
|
||
'admin.mapsKeyHint': 'Необхідний для пошуку місць. Отримайте на console.cloud.google.com',
|
||
'admin.mapsKeyHintLong':
|
||
'Без API-ключа для пошуку місць використовується OpenStreetMap. З ключем Google API можна завантажувати фото, рейтинги та години роботи. Отримайте ключ на console.cloud.google.com.',
|
||
'admin.recommended': 'Рекомендується',
|
||
'admin.weatherKey': 'API-ключ OpenWeatherMap',
|
||
'admin.weatherKeyHint': 'Для даних про погоду. Безкоштовно на openweathermap.org',
|
||
'admin.unsplashKey': 'Ключ API Unsplash',
|
||
'admin.unsplashKeyHint': 'Для пошуку зображень. Безкоштовно на unsplash.com/developers',
|
||
'admin.validateKey': 'Перевірити',
|
||
'admin.keyValid': 'Підключено',
|
||
'admin.keyInvalid': 'Недійсний',
|
||
'admin.keySaved': 'API-ключі збережено',
|
||
'admin.oidcTitle': 'Єдиний вхід (OIDC)',
|
||
'admin.oidcSubtitle': 'Дозволити вхід через зовнішніх провайдерів, таких як Google, Apple, Authentik або Keycloak.',
|
||
'admin.oidcDisplayName': 'Відображуване ім’я',
|
||
'admin.oidcIssuer': 'URL видавця',
|
||
'admin.oidcIssuerHint': 'URL видавця OpenID Connect провайдера. Напр. https://accounts.google.com',
|
||
'admin.oidcSaved': 'Конфігурацію OIDC збережено',
|
||
'admin.oidcOnlyMode': 'Вимкнути вхід за паролем',
|
||
'admin.oidcOnlyModeHint':
|
||
'При ввімкненні дозволено тільки вхід через SSO. Вхід та реєстрація за паролем будуть заблоковані.',
|
||
'admin.fileTypes': 'Дозволені типи файлів',
|
||
'admin.fileTypesHint': 'Налаштуйте, які типи файлів можуть завантажувати користувачі.',
|
||
'admin.fileTypesFormat': 'Розширення через кому (напр. jpg,png,pdf,doc). Використовуйте * для дозволу всіх типів.',
|
||
'admin.fileTypesSaved': 'Налаштування типів файлів збережено',
|
||
'admin.placesPhotos.title': 'Фотографії місць',
|
||
'admin.placesPhotos.subtitle':
|
||
'Завантаження фотографій з Google Places API. Вимкніть для економії квоти API. Фотографії Wikimedia не зачіпаються.',
|
||
'admin.placesAutocomplete.title': 'Автодоповнення місць',
|
||
'admin.placesAutocomplete.subtitle':
|
||
'Використання Google Places API для підказок пошуку. Вимкніть для економії квоти API.',
|
||
'admin.placesDetails.title': 'Відомості про місце',
|
||
'admin.placesDetails.subtitle':
|
||
'Завантаження детальної інформації про місце (години роботи, рейтинг, веб-сайт) з Google Places API. Вимкніть для економії квоти API.',
|
||
'admin.placesEnrich.title': 'Збагачення місць',
|
||
'admin.placesEnrich.subtitle':
|
||
'Показує зображення та опис під час додавання місця. Wikipedia та OpenStreetMap використовуються завжди; Google додається, якщо ввімкнено «Фото місць» або «Деталі місць».',
|
||
'admin.bagTracking.title': 'Відстеження багажу',
|
||
'admin.bagTracking.subtitle': 'Увімкнути вагу та прив’язку до багажу для речей',
|
||
'admin.collab.chat.title': 'Чат',
|
||
'admin.collab.chat.subtitle': 'Обмін повідомленнями для спільної роботи',
|
||
'admin.collab.notes.title': 'Нотатки',
|
||
'admin.collab.notes.subtitle': 'Спільні нотатки та документи',
|
||
'admin.collab.polls.title': 'Опитування',
|
||
'admin.collab.polls.subtitle': 'Групові опитування та голосування',
|
||
'admin.collab.whatsnext.title': 'Що далі',
|
||
'admin.collab.whatsnext.subtitle': 'Пропозиції активностей та наступні кроки',
|
||
'admin.tabs.config': 'Персоналізація',
|
||
'admin.tabs.defaults': 'Налаштування за замовчуванням',
|
||
'admin.defaultSettings.title': 'Налаштування користувачів за замовчуванням',
|
||
'admin.defaultSettings.description':
|
||
'Визначте значення за замовчуванням для всієї інстанції. Користувачі, які не змінювали параметр, побачать ці значення. Їхні власні зміни завжди мають пріоритет.',
|
||
'admin.defaultSettings.saved': 'Значення за замовчуванням збережено',
|
||
'admin.defaultSettings.reset': 'Скинути до вбудованого значення',
|
||
'admin.defaultSettings.resetToBuiltIn': 'скинути',
|
||
'admin.tabs.templates': 'Шаблони пакування',
|
||
'admin.packingTemplates.title': 'Шаблони пакування',
|
||
'admin.packingTemplates.subtitle': 'Створюйте багаторазові списки речей для подорожей',
|
||
'admin.packingTemplates.create': 'Новий шаблон',
|
||
'admin.packingTemplates.namePlaceholder': 'Назва шаблону (наприклад, Відпочинок на пляжі)',
|
||
'admin.packingTemplates.empty': 'Шаблони ще не створені',
|
||
'admin.packingTemplates.items': 'речей',
|
||
'admin.packingTemplates.categories': 'категорії(й)',
|
||
'admin.packingTemplates.itemName': 'Назва речі',
|
||
'admin.packingTemplates.itemCategory': 'Категорія',
|
||
'admin.packingTemplates.categoryName': 'Назва категорії (наприклад, Одяг)',
|
||
'admin.packingTemplates.addCategory': 'Додати категорію',
|
||
'admin.packingTemplates.created': 'Шаблон створено',
|
||
'admin.packingTemplates.deleted': 'Шаблон видалено',
|
||
'admin.packingTemplates.loadError': 'Помилка завантаження шаблонів',
|
||
'admin.packingTemplates.createError': 'Помилка створення шаблону',
|
||
'admin.packingTemplates.deleteError': 'Помилка видалення шаблону',
|
||
'admin.packingTemplates.deleteCategoryError': 'Не вдалося видалити категорію',
|
||
'admin.packingTemplates.deleteItemError': 'Не вдалося видалити елемент',
|
||
'admin.packingTemplates.saveError': 'Помилка збереження',
|
||
'admin.tabs.addons': 'Дополнения',
|
||
'admin.tabs.plugins': 'Плагіни',
|
||
'admin.tabs.storage': 'Сховище',
|
||
'admin.plugins.rescan': 'Пересканувати',
|
||
'admin.plugins.rescanned': 'Папку плагінів пересканувано',
|
||
'admin.plugins.upload': 'Завантажити плагін',
|
||
'admin.plugins.dropToUpload': 'Перетягніть .zip плагіна для встановлення',
|
||
'admin.plugins.uploaded': 'Плагін “{name}” завантажено — активуйте для запуску',
|
||
'admin.plugins.sideloaded': 'Завантажено вручну',
|
||
'admin.plugins.devLinkBadge': 'Dev-Link',
|
||
'admin.plugins.devLinkHint':
|
||
'Завантажено з локального каталогу збірки та гаряче перезавантажується з реальними даними — лише для розробки',
|
||
'admin.plugins.devLinkTitle': 'Підключити локальний плагін',
|
||
'admin.plugins.devLinkPathPlaceholder': '/absolute/path/to/your/plugin',
|
||
'admin.plugins.devLinkButton': 'Підключити',
|
||
'admin.plugins.devLinkLinked': '{id} підключено — активуйте для запуску',
|
||
'admin.plugins.sideloadedHint': 'Завантажено вручну — не з реєстру, без підпису та перевірки',
|
||
'admin.plugins.browse': 'Огляд плагінів',
|
||
'admin.plugins.installed': 'Встановлено',
|
||
'admin.plugins.install': 'Встановити',
|
||
'admin.plugins.registryEmpty': 'У реєстрі поки немає доступних плагінів.',
|
||
'admin.plugins.actionError': 'Не вдалося виконати дію',
|
||
'admin.plugins.activate': 'Активувати',
|
||
'admin.plugins.activated': 'Плагін активовано',
|
||
'admin.plugins.deactivate': 'Деактивувати',
|
||
'admin.plugins.deactivated': 'Плагін деактивовано',
|
||
'admin.plugins.viewErrors': 'Переглянути журнал помилок',
|
||
'admin.plugins.errorLog': 'Журнал помилок',
|
||
'admin.plugins.allowedHosts': 'Дозволені хости',
|
||
'admin.plugins.allowedHosts.hint':
|
||
'Цей плагін звертається до сервісу, який можете вказати лише ви (self-hosted сервер). Додайте хости, до яких він може звертатися — до інших він не зможе.',
|
||
'admin.plugins.allowedHosts.none': 'Хости ще не додано.',
|
||
'admin.plugins.allowedHosts.unsupported':
|
||
'Цей плагін не використовує хости, задані оператором. Його дозволені хости зафіксовані в маніфесті.',
|
||
'admin.plugins.allowedHosts.restartNote': 'Збереження перезапускає плагін, щоб він підхопив новий список.',
|
||
'admin.plugins.allowedHosts.add': 'Додати дозволений хост',
|
||
'admin.plugins.allowedHosts.count': 'Дозволених хостів: {n}',
|
||
'admin.plugins.operatorEgressPill': '+ додані вами хости',
|
||
'admin.plugins.operatorEgressHint':
|
||
'Цей плагін звертається до сервісу, який можете вказати лише ви (self-hosted сервер). Після встановлення додайте хости в ⋯ → Дозволені хости. До інших він не зможе звертатися.',
|
||
'admin.plugins.noErrors': 'Помилок не зафіксовано.',
|
||
'admin.plugins.uninstalled': 'Плагін видалено',
|
||
'admin.plugins.uninstallTitle': 'Видалити плагін?',
|
||
'admin.plugins.uninstallBody': 'Це зупинить плагін, видалить його код і всі його дані. Цю дію не можна скасувати.',
|
||
'admin.plugins.status.starting': 'Запуск…',
|
||
'admin.plugins.type.widget': 'Віджет',
|
||
'admin.plugins.type.page': 'Сторінка',
|
||
'admin.plugins.type.integration': 'Інтеграція',
|
||
'admin.plugins.type.trip-page': 'Сторінка подорожі',
|
||
'admin.plugins.reviewed': 'Перевірено',
|
||
'admin.plugins.unreviewed': 'Не перевірено',
|
||
'admin.plugins.updated': 'Плагін оновлено',
|
||
'admin.plugins.updateTo': 'Оновити → v{version}',
|
||
'admin.plugins.enabledToggle': 'Увімкнути плагін',
|
||
'plugins.notFound': 'Плагін не знайдено',
|
||
'plugins.frameLoadFailed': 'This plugin could not be loaded.',
|
||
'admin.plugins.title': 'Плагіни',
|
||
'admin.plugins.subtitle': 'Встановлюйте сторонні плагіни та керуйте ними на вашому інстансі.',
|
||
'admin.plugins.disabledTitle': 'Плагіни вимкнено',
|
||
'admin.plugins.disabledBody':
|
||
'Середовище виконання плагінів вимкнено (TREK_PLUGINS_ENABLED). Жоден плагін не зможе запуститися, доки адміністратор не ввімкне його в конфігурації сервера.',
|
||
'admin.plugins.empty': 'Плагіни ще не встановлені.',
|
||
'admin.plugins.loadError': 'Не вдалося завантажити плагіни.',
|
||
'admin.plugins.scaffoldNote':
|
||
'Встановлення та активація плагінів з’являться в наступному оновленні. Наразі ця панель лише показує встановлені плагіни.',
|
||
'admin.plugins.status.active': 'Активний',
|
||
'admin.plugins.status.inactive': 'Неактивний',
|
||
'admin.plugins.status.disabled': 'Вимкнено',
|
||
'admin.plugins.status.error': 'Помилка',
|
||
'admin.plugins.status.incompatible': 'Несумісний',
|
||
'admin.plugins.details': 'Деталі',
|
||
'admin.plugins.detailError': 'Не вдалося завантажити деталі плагіна.',
|
||
'admin.plugins.permissionsTitle': 'Дозволи',
|
||
'admin.plugins.noPermissions': 'Цей плагін не запитує особливих дозволів.',
|
||
'admin.plugins.egressNote': 'Може підключатися до: {hosts}',
|
||
'admin.plugins.setupTitle': 'Налаштування',
|
||
'admin.plugins.noSetup': 'Працює одразу — нічого налаштовувати не потрібно.',
|
||
'admin.plugins.scope.instance': 'На весь інстанс',
|
||
'admin.plugins.scope.user': 'Для кожного користувача окремо',
|
||
'admin.plugins.fieldRequired': "Обов'язково",
|
||
'admin.plugins.sourceRepo': 'Репозиторій вихідного коду',
|
||
'admin.plugins.reportIssue': 'Повідомити про проблему',
|
||
'admin.plugins.homepage': 'Домашня сторінка',
|
||
'admin.plugins.requiresTrek': 'Потрібен TREK {version}+',
|
||
'admin.plugins.reviewedOn': 'Перевірено {date}',
|
||
'admin.plugins.perm.db:own': 'Зберігати власні дані в ізольованій базі даних',
|
||
'admin.plugins.perm.db:read:trips': 'Читати подорожі, до яких має доступ поточний користувач',
|
||
'admin.plugins.perm.db:read:users': "Читати базову інформацію профілю (ім'я, аватар — ніколи не облікові дані)",
|
||
'admin.plugins.perm.db:read:costs': 'Читати витрати (статті бюджету), до яких має доступ поточний користувач',
|
||
'admin.plugins.perm.db:read:packing': 'Читати списки речей подорожей, до яких має доступ поточний користувач',
|
||
'admin.plugins.perm.db:write:packing':
|
||
'Створювати, редагувати та видаляти пункти списку речей у подорожах, які може редагувати поточний користувач',
|
||
'admin.plugins.perm.weather:read': 'Читати кешований прогноз погоди хоста (за координатами)',
|
||
'admin.plugins.perm.db:read:categories': 'Читати глобальний список категорій місць',
|
||
'admin.plugins.perm.db:read:tags': 'Читати теги поточного користувача',
|
||
'admin.plugins.perm.db:write:tags': 'Створювати, редагувати та видаляти теги поточного користувача',
|
||
'admin.plugins.perm.db:read:todos': 'Читати завдання подорожей, до яких має доступ поточний користувач',
|
||
'admin.plugins.perm.db:write:todos':
|
||
'Створювати, редагувати та видаляти завдання в подорожах, які може редагувати поточний користувач',
|
||
'admin.plugins.perm.db:write:atlas':
|
||
'Позначати країни та регіони як відвідані та керувати списком бажань поточного користувача (потрібен додаток Atlas)',
|
||
'admin.plugins.perm.db:write:vacay':
|
||
'Перемикати дні відпустки та корпоративні свята в активному плані поточного користувача (потрібен додаток Vacay)',
|
||
'admin.plugins.perm.db:write:journal':
|
||
'Створювати, редагувати та видаляти записи в щоденниках, які може редагувати поточний користувач (потрібен додаток Journey)',
|
||
'admin.plugins.perm.db:write:collections':
|
||
'Створювати та редагувати колекції й зберігати в них місця з роллю поточного користувача в колекції (потрібен додаток Collections)',
|
||
'admin.plugins.perm.db:write:files':
|
||
"Прикріплювати файли до подорожей, які може редагувати поточний користувач (ліміт 10 МБ, заблоковані розширення відхиляються), і керувати їхніми зв'язками",
|
||
'admin.plugins.perm.db:write:collab':
|
||
'Публікувати нотатки, опитування та повідомлення чату в подорожах, які може редагувати поточний користувач (потрібен додаток Collab)',
|
||
'admin.plugins.perm.db:write:members':
|
||
'Додавати користувачів до подорожей — надає доступ до подорожі; захищено правом керування учасниками поточного користувача',
|
||
'admin.plugins.perm.notify:send':
|
||
'Надсилати сповіщення (скринька дзвіночка + email/ntfy) поточному користувачеві або його подорожі — ніколи довільному одержувачу',
|
||
'admin.plugins.perm.ai:invoke':
|
||
'Використовувати налаштованого адміністратором ШІ-провайдера (доповнення тексту + видобування з документів) від імені поточного користувача — плагін ніколи не зберігає ключ',
|
||
'admin.plugins.perm.oauth:client':
|
||
'Підключення до сторонньої служби від вашого імені через OAuth за посередництва хоста (хост зберігає токени, плагін їх не бачить)',
|
||
'admin.plugins.perm.db:read:files': 'Читати файли подорожей, до яких має доступ поточний користувач',
|
||
'admin.plugins.perm.db:write:reservations':
|
||
'Створювати, редагувати та видаляти бронювання в подорожах, які може редагувати поточний користувач',
|
||
'admin.plugins.perm.db:write:accommodations':
|
||
'Створювати, редагувати та видаляти проживання в подорожах, які може редагувати поточний користувач',
|
||
'admin.plugins.perm.db:read:journal': 'Читати щоденники подорожей поточного користувача (потрібен додаток Journey)',
|
||
'admin.plugins.perm.db:read:atlas':
|
||
'Читати відвідані країни та регіони поточного користувача (потрібен додаток Atlas)',
|
||
'admin.plugins.perm.db:read:vacay': 'Читати план відпустки поточного користувача (потрібен додаток Vacay)',
|
||
'admin.plugins.perm.db:read:daynotes': 'Читати нотатки дня подорожей, до яких має доступ поточний користувач',
|
||
'admin.plugins.perm.db:read:collections':
|
||
'Читати колекції збережених місць поточного користувача (потрібен додаток Collections)',
|
||
'admin.plugins.perm.db:write:daynotes':
|
||
'Створювати, редагувати та видаляти нотатки дня в подорожах, які може редагувати поточний користувач',
|
||
'admin.plugins.perm.jobs:run':
|
||
'Запускати оголошені фонові завдання за розкладом (без контексту користувача — не може читати дані користувача)',
|
||
'admin.plugins.perm.db:write:costs':
|
||
'Створювати витрати (статті бюджету) у подорожах, які може редагувати поточний користувач',
|
||
'admin.plugins.perm.db:write:places':
|
||
'Додавати, редагувати та видаляти місця в подорожах, які може редагувати поточний користувач',
|
||
'admin.plugins.perm.db:write:days':
|
||
'Додавати, редагувати та видаляти дні в подорожах, які може редагувати поточний користувач',
|
||
'admin.plugins.perm.db:write:itinerary':
|
||
'Призначати та видаляти місця в днях подорожей, які може редагувати поточний користувач',
|
||
'admin.plugins.perm.db:write:trips':
|
||
'Редагувати деталі подорожі (назва, дати, валюта…) у подорожах, які може редагувати поточний користувач',
|
||
'admin.plugins.perm.db:meta':
|
||
'Прикріплювати власні приватні дані до подорожей, місць і днів, до яких має доступ поточний користувач',
|
||
'admin.plugins.perm.ws:broadcast:trip': 'Надсилати оновлення в реальному часі учасникам подорожі',
|
||
'admin.plugins.perm.ws:broadcast:user': 'Надсилати оновлення в реальному часі окремим користувачам',
|
||
'admin.plugins.perm.hook:photo-provider': 'Надавати фотографії для Спогадів',
|
||
'admin.plugins.perm.hook:calendar-source': 'Надавати події для календаря',
|
||
'admin.plugins.perm.hook:place-detail-provider': 'Додавати додаткові деталі (відгуки, оцінки, посилання) до місця',
|
||
'admin.plugins.perm.hook:trip-warning-provider':
|
||
'Створювати попередження перевірки для подорожі (показуються в планувальнику)',
|
||
'admin.plugins.perm.hook:table-contributor': 'Додавати стовпці та дії до подань подорожі (бронювання, місця, дні)',
|
||
'admin.plugins.perm.hook:map-marker-provider':
|
||
'Додавати мітки на карту подорожі (наприклад, показувати бронювання або POI)',
|
||
'admin.plugins.perm.hook:map-layer-provider': 'Малювати маршрути, коридори та зони на карті подорожі',
|
||
'admin.plugins.perm.hook:route-provider':
|
||
'Надавати профілі маршрутизації, за якими планувальник будує маршрути днів (наприклад, маршрути для електромобілів із зупинками для заряджання)',
|
||
'admin.plugins.perm.hook:day-schedule-provider':
|
||
'Додавати часові записи до плану дня (зупинки для заряджання, буфери часу)',
|
||
'admin.plugins.perm.hook:day-tint-provider':
|
||
'Позначати дні в плані дня кольором (наприклад, до якого етапу подорожі належить день)',
|
||
'admin.plugins.cap.mcpTools': 'Публікує ШІ-інструменти',
|
||
'admin.plugins.mcpToolsTitle': 'Опубліковані ШІ-інструменти',
|
||
'admin.plugins.mcpToolsHint': 'Асистент може запускати їх від імені користувача. Кожен діє з правами, наданими вище.',
|
||
'admin.plugins.perm.mcp:tools':
|
||
'Публікувати інструменти, які ШІ-асистент може запускати від вашого імені (він діє з правами, наданими плаґіну тут, а не зі своїми)',
|
||
'admin.plugins.perm.geolocation:read':
|
||
'Запитувати ваше місцезнаходження в реальному часі, поки відкрито одне з його подань (TREK зчитує його з дозволом на геолокацію для цього сайту, а не з окремим дозволом розширення)',
|
||
'admin.plugins.perm.hook:pdf-section-provider': 'Додавати текстові розділи до PDF-експорту подорожі',
|
||
'admin.plugins.perm.hook:atlas-layer-provider':
|
||
'Виділяти країни на карті світу в Атласі (наприклад, списки бажань або попередження для мандрівників)',
|
||
'admin.plugins.perm.hook:journal-entry-provider':
|
||
'Додавати додаткові рядки (посилання, статистику) до записів щоденника',
|
||
'admin.plugins.perm.hook:user-data':
|
||
'Видалення або експорт збережених даних про користувача (GDPR: видалення акаунта та запити даних)',
|
||
'admin.plugins.perm.hook:trip-card-provider':
|
||
'Додавати невеликі значки (статус, лічильники) на картки подорожей на панелі',
|
||
'admin.plugins.perm.hook:notification-channel': 'Доставляти ваші сповіщення через додатковий канал',
|
||
'admin.plugins.perm.events:subscribe':
|
||
'Реагувати на основні події активності (лише назва події + подорож, ніколи вміст)',
|
||
'admin.plugins.perm.http:outbound': 'Виконувати вихідні запити до заявлених хостів',
|
||
'admin.plugins.perm.db:read:collab':
|
||
'Читати нотатки, опитування та повідомлення чату подорожей, до яких має доступ поточний користувач (потрібен додаток Collab)',
|
||
'admin.plugins.perm.db:read:files:content':
|
||
'Читати вміст (байти) файлів подорожей, до яких має доступ поточний користувач',
|
||
'admin.plugins.perm.db:create:trips': 'Створювати нові подорожі, що належать поточному користувачеві',
|
||
'admin.plugins.perm.rates:read': 'Читати кешовані курси валют хоста',
|
||
'admin.plugins.updateConsentTitle': 'Це оновлення потребує нових дозволів',
|
||
'admin.plugins.updateConsentBody':
|
||
'{name} v{version} запитує права, які ви ще не надали. Нову версію встановлено, але вона залишається вимкненою, доки ви її не схвалите.',
|
||
'admin.plugins.updateNewPermissions': 'Нові запитані дозволи',
|
||
'admin.plugins.updateNewEgress': 'Нові вихідні підключення',
|
||
'admin.plugins.updateApprove': 'Схвалити та увімкнути',
|
||
'admin.plugins.updateLater': 'Поки що залишити вимкненим',
|
||
'admin.plugins.updateKeptOff': 'Оновлення встановлено — залишено вимкненим, доки ви не схвалите нові дозволи',
|
||
'admin.plugins.reviewedMeaning':
|
||
'«Перевірено» означає, що супроводжувач TREK перевіряв цей плагін на наявність шкідливого коду в кожній версії — а не на якість чи працездатність. Це не гарантія того, що плагін безпечний.',
|
||
'admin.plugins.security.title': 'Як обмежуються плагіни — і де їхні межі',
|
||
'admin.plugins.security.isolationTitle': 'Кожен плагін працює в ізоляції',
|
||
'admin.plugins.security.isolationBody':
|
||
'Плагін працює як власний ізольований процес, який може читати лише свої власні файли. Він не може читати вашу базу даних, ваш секрет входу чи ваш ключ шифрування, не може запускати інші програми та не може записувати файли будь-де. Його інтерфейс працює в ізольованому фреймі браузера, який не може читати ваш файл cookie сеансу чи торкатися сторінки TREK навколо нього.',
|
||
'admin.plugins.security.permsTitle': 'Що означають дозволи',
|
||
'admin.plugins.security.permsBody':
|
||
'Дозволи, показані перед встановленням, — це жорстке обмеження, яке TREK застосовує під час роботи плагіна: він буквально не може зробити нічого, чого немає у списку. Але вони говорять, що плагін може робити, а не що він насправді робить. Плагін, якому дозволено читати ваші подорожі та звертатися до сервера, може надіслати ваші подорожі на цей сервер, тож читайте дозволи та вихідні хости, а не лише опис.',
|
||
'admin.plugins.security.limitsTitle': 'Чого ми не можемо обіцяти',
|
||
'admin.plugins.security.limitsBody':
|
||
'Ізоляція — це надійна програмна межа, але не абсолютна. Плагін діє рівно з тими правами, які ви схвалили, тож у межах цих прав він може поводитися інакше, ніж описано, і може надсилати дані, якими законно володіє, на заявлені ним хости. TREK не читає й не оцінює, що насправді робить код плагіна.',
|
||
'admin.plugins.security.worstTitle': 'Найгірший випадок',
|
||
'admin.plugins.security.worstBody':
|
||
'Шкідливий плагін, який ви увімкнули, може зловживати даними та підключеннями, які ви йому надали, — наприклад, розкрити подорожі, які йому дозволено читати. Він не може викрасти паролі, підробити вхід адміністратора, виконувати команди на вашому сервері чи отримати доступ до даних, яких ви не надали. Шкода залишається в межах того, що ви схвалили, а вимкнення плагіна зупиняє її.',
|
||
'admin.plugins.security.reviewedTitle': 'Що означає «Перевірено»',
|
||
'admin.plugins.security.reviewedBody':
|
||
'Перевірений плагін вручну сканував супроводжувач TREK на наявність шкідливого коду в кожній версії — перевіряли на ворожий код, а не на те, чи добре він працює. Це не обіцянка, що плагін безпечний.',
|
||
'admin.plugins.security.signedTitle': 'Що означає «Підписано»',
|
||
'admin.plugins.security.signedBody':
|
||
'Контрольна сума, яку TREK перевіряє під час кожного встановлення, доводить, що файли — це саме те, за що ручається реєстр. Підпис доводить інше: що вони походять від автора й підписані ключем, який є лише в нього. Підписаний плагін має і те, і те. Плагін без підпису не є небезпечним — він просто дає на одну гарантію менше, і сьогодні більшість плагінів у реєстрі не підписані.',
|
||
'admin.plugins.signed': 'Підписано',
|
||
'admin.plugins.signedHint': 'Під час встановлення перевірено за ключем підпису автора',
|
||
'admin.plugins.unsigned': 'Без підпису',
|
||
'admin.plugins.unsignedHint':
|
||
"Файли збігаються з тим, за що ручається реєстр, але ніщо не пов'язує їх з автором. На одну гарантію менше — але це не небезпечно.",
|
||
'admin.plugins.updateBlocked': 'Оновлення заблоковано — {reason}',
|
||
'admin.plugins.reviewBlock': 'Переглянути',
|
||
'admin.plugins.retrusted': 'Новому ключу підпису надано довіру — плагін оновлено',
|
||
'admin.plugins.sig.title': 'Не вдалося перевірити підпис плагіна «{name}»',
|
||
'admin.plugins.sig.keyChangedBody':
|
||
'Ключ підпису автора не той, з яким цей плагін було встановлено. Автори справді змінюють ключі — але зловмисник, який захопив плагін, виглядав би точнісінько так само.',
|
||
'admin.plugins.sig.invalidBody':
|
||
'Файли не відповідають підпису автора. Це не те, що підписав автор — їх або пошкоджено, або підмінено. Це не можна обійти.',
|
||
'admin.plugins.sig.missingBody':
|
||
'Цей плагін був підписаний, коли ви його встановлювали, але нова версія не має підпису. TREK не прийме таке пониження мовчки. Це не можна обійти.',
|
||
'admin.plugins.sig.incompleteBody':
|
||
'Запис у реєстрі підписаний наполовину: він оголошує ключ автора, але версія не має підпису (або навпаки). Це помилка на боці плагіна. Це не можна обійти.',
|
||
'admin.plugins.sig.pinnedKey': 'Ключ, з яким його встановлено',
|
||
'admin.plugins.sig.newKey': 'Ключ, який він пропонує зараз',
|
||
'admin.plugins.sig.confirmOutOfBand':
|
||
'TREK не може відрізнити законну зміну ключа від захоплення — звідси вони виглядають однаково. Перш ніж прийняти новий ключ, підтвердьте його в автора через канал, якому ви вже довіряєте. Щойно ви це зробите, плагін буде оновлено, а новий ключ — збережено.',
|
||
'admin.plugins.sig.retrustConfirm': 'Довіряти новому ключу й оновити',
|
||
'admin.plugins.sig.cancel': 'Не довіряти',
|
||
'admin.plugins.sig.consentUnsigned':
|
||
"Ніщо не пов'язує цю версію з її автором — файли збігаються з реєстром, але не мають підпису автора.",
|
||
'admin.plugins.security.trustTitle': 'Підсумок',
|
||
'admin.plugins.security.trustBody':
|
||
'Встановлення плагіна — це те саме, що встановлення будь-якого стороннього застосунку: додавайте лише код від авторів, яким довіряєте, а в разі сумнівів спершу перевірте його самостійно. TREK не несе відповідальності за сторонні плагіни.',
|
||
'admin.plugins.runtimeOn': 'Середовище виконання ввімкнено',
|
||
'admin.plugins.tabDiscover': 'Огляд',
|
||
'admin.plugins.searchPlaceholder': 'Пошук плагінів…',
|
||
'admin.plugins.filterType': 'Тип',
|
||
'admin.plugins.filterStatus': 'Статус',
|
||
'admin.plugins.sortBy': 'Сортування',
|
||
'admin.plugins.allTypes': 'Усі типи',
|
||
'admin.plugins.allStatuses': 'Усі',
|
||
'admin.plugins.stateOff': 'Вимкнено',
|
||
'admin.plugins.filterUpdate': 'Доступне оновлення',
|
||
'admin.plugins.sortName': 'Назва',
|
||
'admin.plugins.sortRecent': 'Нещодавно оновлені',
|
||
'admin.plugins.sortUpdates': 'Спочатку оновлення',
|
||
'admin.plugins.sortDownloads': 'За завантаженнями',
|
||
'admin.plugins.updatesAvailable': 'Для ваших плагінів доступно оновлень: {count}.',
|
||
'admin.plugins.newerNeedsTrek': 'Доступна v{version} — потрібен TREK {range}',
|
||
'admin.plugins.versionsTitle': 'Версії',
|
||
'admin.plugins.versionPickerTitle': 'Змінити версію — {name}',
|
||
'admin.plugins.versionSwitch': 'Перейти на {version}',
|
||
'admin.plugins.versionNeedsTrek': 'потрібен TREK {range}',
|
||
'admin.plugins.changeVersion': 'Змінити версію…',
|
||
'admin.plugins.noVersions': 'У реєстрі не знайдено опублікованих версій.',
|
||
'admin.plugins.downgradeTitle': 'Відкотити цей плагін?',
|
||
'admin.plugins.downgradeBody': 'Перехід з v{from} на v{to}: дані, записані новішою версією, залишаються, і старіша версія може їх не розуміти.',
|
||
'admin.plugins.downgradeConfirm': 'Відкотити',
|
||
'admin.plugins.updatesHeld': 'Оновлення призупинено на v{version}',
|
||
'admin.plugins.resumeUpdates': 'Відновити оновлення',
|
||
'admin.plugins.updatesResumed': 'Оновлення відновлено',
|
||
'admin.plugins.updateAll': 'Оновити все',
|
||
'admin.plugins.noMatchInstalled': 'Жоден встановлений плагін не відповідає вашому запиту.',
|
||
'admin.plugins.noMatchRegistry': 'Жоден плагін у реєстрі не відповідає вашому запиту.',
|
||
'admin.plugins.restart': 'Перезапустити',
|
||
'admin.plugins.restarted': 'Плагін перезапущено',
|
||
'admin.plugins.instanceSettings': 'Налаштування інстансу',
|
||
'admin.plugins.settingsSaved': 'Налаштування збережено',
|
||
'admin.plugins.settingsSavedRestarted': 'Налаштування збережено — плагін перезапущено',
|
||
'admin.plugins.cap.readsTrips': 'Читає ваші подорожі',
|
||
'admin.plugins.cap.readsUsers': 'Читає базові профілі',
|
||
'admin.plugins.cap.readsCosts': 'Читає ваші витрати',
|
||
'admin.plugins.cap.readsPacking': 'Читає списки речей',
|
||
'admin.plugins.cap.readsFiles': 'Читає файли подорожей',
|
||
'admin.plugins.cap.writesCosts': 'Додає витрати',
|
||
'admin.plugins.cap.writesPlaces': 'Редагує місця',
|
||
'admin.plugins.cap.writesDays': 'Редагує дні',
|
||
'admin.plugins.cap.writesItinerary': 'Редагує маршрут',
|
||
'admin.plugins.cap.writesTrips': 'Редагує подорожі',
|
||
'admin.plugins.cap.metadata': 'Додає метадані',
|
||
'admin.plugins.cap.widget': 'Віджет панелі',
|
||
'admin.plugins.cap.heroWidget': 'Віджет посадкового талона',
|
||
'admin.plugins.cap.placeSlot': 'Деталі місця',
|
||
'admin.plugins.cap.daySlot': 'Деталі дня',
|
||
'admin.plugins.cap.reservationSlot': 'Деталі бронювання',
|
||
'admin.plugins.cap.replacesTabs': 'Замінює вкладки планувальника',
|
||
'admin.plugins.cap.realtime': 'Оновлення в реальному часі',
|
||
'admin.plugins.cap.notificationChannel': 'Канал сповіщень',
|
||
'admin.plugins.cap.photos': 'Надає фотографії',
|
||
'admin.plugins.cap.calendar': 'Надає події календаря',
|
||
'admin.plugins.cap.placeDetails': 'Збагачує місця',
|
||
'admin.plugins.cap.warnings': 'Позначає проблеми',
|
||
'admin.plugins.cap.mapLayers': 'Малює на карті',
|
||
'admin.plugins.cap.routing': 'Пропонує маршрутизацію',
|
||
'admin.plugins.cap.daySchedule': 'Додає часи до плану',
|
||
'admin.plugins.cap.dayTint': 'Розфарбовує дні',
|
||
'admin.plugins.cap.geolocation': 'Читає ваше місцезнаходження',
|
||
'admin.plugins.cap.events': 'Реагує на активність',
|
||
'admin.plugins.cap.requiresAddon': 'Потрібен {addon}',
|
||
'admin.plugins.cap.dependsOn': 'Потрібен {id} {version}',
|
||
'admin.plugins.dep.addonDisabledToast': 'Спершу увімкніть потрібні доповнення: {addons}',
|
||
'admin.plugins.dep.autoEnabled': 'Спершу увімкнено потрібні плагіни: {plugins}',
|
||
'admin.plugins.dep.downloaded': 'Завантажено {id}',
|
||
'admin.plugins.dep.resolveTitle': 'Відсутні залежності',
|
||
'admin.plugins.dep.resolveBody': '“{name}” потребує встановлення цих плагінів, перш ніж його можна буде увімкнути.',
|
||
'admin.plugins.dep.requires': 'Потрібен {version}',
|
||
'admin.plugins.dep.mismatch': 'Потрібен {wanted} — встановлено {installed}',
|
||
'admin.plugins.dep.download': 'Завантажити',
|
||
'admin.plugins.dep.update': 'Оновити',
|
||
'admin.plugins.dep.resolveHint': 'Завантажує останню сумісну версію разом з її залежностями.',
|
||
'admin.plugins.dep.trekIncompatible': 'Потрібен TREK {range} — на цьому сервері {host}',
|
||
'admin.plugins.dep.trekUnknown': 'Не вказано, які версії TREK підтримуються',
|
||
'admin.plugins.installCompatible': 'Встановити {version}',
|
||
'admin.plugins.incompatible': 'Несумісно',
|
||
'admin.plugins.accessTitle': 'До чого має доступ',
|
||
'admin.plugins.connectsTitle': 'Підключається до',
|
||
'admin.plugins.detailsTitle': 'Деталі',
|
||
'admin.plugins.noAccess': 'Не потребує особливого доступу.',
|
||
'admin.plugins.metaVersion': 'Версія',
|
||
'admin.plugins.metaSize': 'Розмір',
|
||
'admin.plugins.metaRequires': 'Потребує',
|
||
'admin.plugins.metaReviewed': 'Перевірено',
|
||
'admin.plugins.downloads': 'Завантаження',
|
||
'admin.addons.title': 'Доповнення',
|
||
'admin.addons.subtitle': 'Увімкніть або вимкніть функції, щоб налаштувати TREK під себе.',
|
||
'admin.addons.catalog.memories.name': 'Фото (Immich)',
|
||
'admin.addons.catalog.memories.description': 'Діліться фотографіями з подорожей через Immich',
|
||
'admin.addons.catalog.mcp.name': 'MCP',
|
||
'admin.addons.catalog.mcp.description': 'Протокол контексту моделі для інтеграції з ІІ-асистентами',
|
||
'admin.addons.catalog.packing.name': 'Списки',
|
||
'admin.addons.catalog.packing.description': 'Списки речей та завдання для ваших подорожей',
|
||
'admin.addons.catalog.budget.name': 'Витрати',
|
||
'admin.addons.catalog.budget.description': 'Відстежуйте витрати та плануйте бюджет подорожі',
|
||
'admin.addons.catalog.documents.name': 'Документи',
|
||
'admin.addons.catalog.documents.description': 'Зберігайте та керуйте документами для подорожей',
|
||
'admin.addons.catalog.vacay.name': 'Vacay',
|
||
'admin.addons.catalog.vacay.description': 'Особистий планувальник відпусток з календарем',
|
||
'admin.addons.catalog.atlas.name': 'Atlas',
|
||
'admin.addons.catalog.atlas.description': 'Карта світу з відвіданими країнами та статистикою подорожей',
|
||
'admin.addons.catalog.collab.name': 'Collab',
|
||
'admin.addons.catalog.collab.description': 'Нотатки в реальному часі, опитування та чат для планування подорожей',
|
||
'admin.addons.subtitleBefore': 'Увімкніть або вимкніть функції для налаштування ',
|
||
'admin.addons.subtitleAfter': ' під себе.',
|
||
'admin.addons.enabled': 'Увімкнено',
|
||
'admin.addons.disabled': 'Вимкнено',
|
||
'admin.addons.type.trip': 'Поїздка',
|
||
'admin.addons.type.global': 'Глобально',
|
||
'admin.addons.type.integration': 'Інтеграція',
|
||
'admin.addons.tripHint': 'Доступно як вкладка всередині кожної подорожі',
|
||
'admin.addons.globalHint': 'Доступно як окремий розділ у головній навігації',
|
||
'admin.addons.integrationHint': 'Фонові сервіси та API-інтеграції без окремої сторінки',
|
||
'admin.addons.toast.updated': 'Доповнення оновлено',
|
||
'admin.addons.toast.error': 'Не вдалося оновити доповнення',
|
||
'admin.addons.noAddons': 'Немає доступних доповнень',
|
||
'admin.weather.title': 'Дані про погоду',
|
||
'admin.weather.badge': 'З 24 березня 2026',
|
||
'admin.weather.description':
|
||
'TREK використовує Open-Meteo як джерело даних про погоду. Open-Meteo — безкоштовний сервіс з відкритим кодом, API-ключ не потрібен.',
|
||
'admin.weather.forecast': 'Прогноз на 16 днів',
|
||
'admin.weather.forecastDesc': 'Раніше 5 днів (OpenWeatherMap)',
|
||
'admin.weather.climate': 'Історичні кліматичні дані',
|
||
'admin.weather.climateDesc': 'Середні значення за останні 85 років для днів поза межами 16-денного прогнозу',
|
||
'admin.weather.requests': '10 000 запитів / день',
|
||
'admin.weather.requestsDesc': 'Безкоштовно, API-ключ не потрібен',
|
||
'admin.weather.locationHint':
|
||
'Погода базується на першому місці з координатами в кожному дні. Якщо жодне місце не призначено на день, як орієнтир використовується будь-яке місце зі списку.',
|
||
'admin.tabs.mcpTokens': 'MCP-доступ',
|
||
'admin.mcpTokens.title': 'MCP-доступ',
|
||
'admin.mcpTokens.subtitle': 'Управління OAuth-сеансами та API-токенами всіх користувачів',
|
||
'admin.mcpTokens.sectionTitle': 'API-токени',
|
||
'admin.mcpTokens.owner': 'Власник',
|
||
'admin.mcpTokens.tokenName': 'Назва токена',
|
||
'admin.mcpTokens.created': 'Створено',
|
||
'admin.mcpTokens.lastUsed': 'Останнє використання',
|
||
'admin.mcpTokens.never': 'Ніколи',
|
||
'admin.mcpTokens.empty': 'MCP-токени ще не створені',
|
||
'admin.mcpTokens.deleteTitle': 'Видалити токен',
|
||
'admin.mcpTokens.deleteMessage': 'Токен буде негайно відкликано. Користувач втратить доступ до MCP через цей токен.',
|
||
'admin.mcpTokens.deleteSuccess': 'Токен видалено',
|
||
'admin.mcpTokens.deleteError': 'Не вдалося видалити токен',
|
||
'admin.mcpTokens.loadError': 'Не вдалося завантажити токени',
|
||
'admin.oauthSessions.sectionTitle': 'OAuth-сеанси',
|
||
'admin.oauthSessions.clientName': 'Клієнт',
|
||
'admin.oauthSessions.owner': 'Власник',
|
||
'admin.oauthSessions.scopes': 'Права доступу',
|
||
'admin.oauthSessions.created': 'Створено',
|
||
'admin.oauthSessions.empty': 'Немає активних OAuth-сеансів',
|
||
'admin.oauthSessions.revokeTitle': 'Відкликати сеанс',
|
||
'admin.oauthSessions.revokeMessage': 'Цей OAuth-сеанс буде негайно відкликаний. Клієнт втратить доступ до MCP.',
|
||
'admin.oauthSessions.revokeSuccess': 'Сеанс відкликано',
|
||
'admin.oauthSessions.revokeError': 'Не вдалося відкликати сеанс',
|
||
'admin.oauthSessions.loadError': 'Не вдалося завантажити OAuth-сеанси',
|
||
'admin.tabs.github': 'GitHub',
|
||
'admin.audit.subtitle':
|
||
'Події, пов’язані з безпекою та адмініструванням (резервні копії, користувачі, MFA, налаштування).',
|
||
'admin.audit.empty': 'Записів аудиту поки немає.',
|
||
'admin.audit.refresh': 'Оновити',
|
||
'admin.audit.loadMore': 'Завантажити ще',
|
||
'admin.audit.showing': 'Завантажено: {count} · всього {total}',
|
||
'admin.audit.col.time': 'Час',
|
||
'admin.audit.col.user': 'Користувач',
|
||
'admin.audit.col.action': 'Дія',
|
||
'admin.audit.col.resource': 'Об’єкт',
|
||
'admin.audit.col.ip': 'IP',
|
||
'admin.audit.col.details': 'Деталі',
|
||
'admin.github.title': 'Історія релізів',
|
||
'admin.github.subtitle': 'Останні оновлення з {repo}',
|
||
'admin.github.latest': 'Останній',
|
||
'admin.github.prerelease': 'Пререліз',
|
||
'admin.github.showDetails': 'Показати деталі',
|
||
'admin.github.hideDetails': 'Сховати деталі',
|
||
'admin.github.loadMore': 'Завантажити ще',
|
||
'admin.github.loading': 'Завантаження...',
|
||
'admin.github.support': 'Допомагає продовжувати розробку TREK',
|
||
'admin.github.error': 'Не вдалося завантажити релізи',
|
||
'admin.github.by': 'від',
|
||
'admin.update.available': 'Доступне оновлення',
|
||
'admin.update.text': 'Доступна версія TREK {version}. У вас встановлено {current}.',
|
||
'admin.update.button': 'Переглянути на GitHub',
|
||
'admin.update.install': 'Встановити оновлення',
|
||
'admin.update.confirmTitle': 'Встановити оновлення?',
|
||
'admin.update.confirmText': 'TREK буде оновлено з {current} до {version}. Сервер перезапуститься автоматично.',
|
||
'admin.update.dataInfo':
|
||
'Усі ваші дані (поїздки, користувачі, API-ключі, завантаження, Vacay, Atlas, бюджети) будуть збережені.',
|
||
'admin.update.warning': 'Застосунок буде тимчасово недоступний під час перезапуску.',
|
||
'admin.update.confirm': 'Оновити зараз',
|
||
'admin.update.installing': 'Оновлення…',
|
||
'admin.update.success': 'Оновлення встановлено! Сервер перезапускається…',
|
||
'admin.update.failed': 'Помилка оновлення',
|
||
'admin.update.backupHint': 'Рекомендуємо створити резервну копію перед оновленням.',
|
||
'admin.update.backupLink': 'Перейти до резервних копій',
|
||
'admin.update.howTo': 'Як оновити',
|
||
'admin.update.dockerText':
|
||
'Ваш екземпляр TREK працює в Docker. Для оновлення до {version} виконайте ці команди на сервері:',
|
||
'admin.update.nonDockerText':
|
||
'Цей екземпляр TREK не працює в Docker. Щоб оновити до {version}, повторно запустіть метод встановлення або оновлення, який ви використовували, — наприклад, у Proxmox Community Scripts запустіть оновлення з консолі LXC:',
|
||
'admin.update.wikiLink': 'Відкрити інструкцію з оновлення',
|
||
'admin.update.reloadHint': 'Перезавантажте сторінку через кілька секунд.',
|
||
'admin.tabs.permissions': 'Дозволи',
|
||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||
'admin.notifications.inappPanel.title': 'In-App',
|
||
'admin.notifications.inappPanel.hint': 'Сповіщення в додатку завжди активні і не можуть бути вимкнені глобально.',
|
||
'admin.notifications.adminWebhookPanel.title': 'Webhook адміністратора',
|
||
'admin.notifications.adminWebhookPanel.hint':
|
||
'Цей webhook використовується виключно для сповіщень адміністратора (наприклад, повідомлень про версії). Він незалежить від користувацьких вебхуків і надсилається автоматично при наявності URL.',
|
||
'admin.notifications.adminWebhookPanel.saved': 'URL вебхука адміністратора збережено',
|
||
'admin.notifications.adminWebhookPanel.testSuccess': 'Тестовий webhook успішно надіслано',
|
||
'admin.notifications.adminWebhookPanel.testFailed': 'Помилка тестового вебхука',
|
||
'admin.notifications.adminWebhookPanel.alwaysOnHint':
|
||
'Webhook адміністратора надсилається автоматично при наявності URL',
|
||
'admin.notifications.ntfy': 'Ntfy',
|
||
'admin.ntfy.hint':
|
||
'Дозволяє користувачам налаштовувати власні теми Ntfy для push-сповіщень. Встановіть сервер за замовчуванням нижче, щоб попередньо заповнити налаштування користувачів.',
|
||
'admin.notifications.testNtfy': 'Надіслати тестовий Ntfy',
|
||
'admin.notifications.testNtfySuccess': 'Тестовий Ntfy успішно надіслано',
|
||
'admin.notifications.testNtfyFailed': 'Помилка надсилання тестового Ntfy',
|
||
'admin.notifications.adminNtfyPanel.title': 'Ntfy адміністратора',
|
||
'admin.notifications.adminNtfyPanel.hint':
|
||
'Ця тема Ntfy використовується виключно для сповіщень адміністратора (наприклад, повідомлень про версії). Вона незалежна від тем користувачів і завжди надсилається при наявності налаштування.',
|
||
'admin.notifications.adminNtfyPanel.serverLabel': 'URL сервера Ntfy',
|
||
'admin.notifications.adminNtfyPanel.serverHint':
|
||
'Також використовується як сервер за замовчуванням для ntfy-сповіщень користувачів. Залиште пустим, щоб використовувати ntfy.sh. Користувачі можуть змінити це в своїх налаштуваннях.',
|
||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||
'admin.notifications.adminNtfyPanel.topicLabel': 'Тема адміністратора',
|
||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Токен доступу (необов’язково)',
|
||
'admin.notifications.adminNtfyPanel.tokenCleared': 'Токен доступу адміністратора очищено',
|
||
'admin.notifications.adminNtfyPanel.saved': 'Налаштування Ntfy адміністратора збережено',
|
||
'admin.notifications.adminNtfyPanel.test': 'Надіслати тестовий Ntfy',
|
||
'admin.notifications.adminNtfyPanel.testSuccess': 'Тестовий Ntfy успішно надіслано',
|
||
'admin.notifications.adminNtfyPanel.testFailed': 'Помилка надсилання тестового Ntfy',
|
||
'admin.notifications.adminNtfyPanel.alwaysOnHint':
|
||
'Ntfy адміністратора завжди надсилається при наявності налаштованої теми',
|
||
'admin.notifications.adminNotificationsHint':
|
||
'Налаштуйте, які канали доставляють сповіщення адміністратора (наприклад, повідомлення про версії). Вебхук надсилається автоматично, якщо задано URL вебхука адміністратора.',
|
||
'admin.notifications.tripReminders.title': 'Нагадування про поїздки',
|
||
'admin.notifications.tripReminders.hint':
|
||
'Надсилає нагадування перед початком поїздки (необхідно вказати дні нагадування в параметрах поїздки).',
|
||
'admin.notifications.tripReminders.enabled': 'Нагадування про поїздки увімкнено',
|
||
'admin.notifications.tripReminders.disabled': 'Нагадування про поїздки вимкнено',
|
||
'admin.tabs.notifications': 'Сповіщення',
|
||
'admin.addons.catalog.journey.name': 'Journey',
|
||
'admin.addons.catalog.journey.description':
|
||
'Відстеження поїздок і щоденник подорожей з позначками, фото та щоденними історіями',
|
||
'admin.addons.catalog.collections.name': 'Колекції',
|
||
'admin.addons.catalog.collections.description':
|
||
'Особиста бібліотека місць — зберігайте місця з різних подорожей у іменовані списки, копіюйте в будь-яку подорож, діліться з іншими',
|
||
'admin.passkey.title': 'Вхід за допомогою passkey',
|
||
'admin.passkey.cardHint':
|
||
'Дозволити користувачам входити за допомогою passkey (WebAuthn). За замовчуванням вимкнено.',
|
||
'admin.passkey.login': 'Увімкнути вхід за допомогою passkey',
|
||
'admin.passkey.loginHint':
|
||
'Показувати опцію «Увійти за допомогою passkey» та дозволити користувачам реєструвати passkeys у своїх налаштуваннях.',
|
||
'admin.passkey.notConfigured':
|
||
'Для цього розгортання поки не визначено жодного домену WebAuthn. Вкажіть APP_URL або Relying Party ID нижче — до того часу passkeys залишатимуться прихованими.',
|
||
'admin.passkey.rpId': 'Relying Party ID (домен)',
|
||
'admin.passkey.rpIdHint':
|
||
'Чистий домен, до якого прив’язані passkeys, напр. trek.example.org. Залиште порожнім, щоб визначити його з APP_URL. Подальша зміна робить наявні passkeys недійсними.',
|
||
'admin.passkey.origins': 'Дозволені джерела (origins)',
|
||
'admin.passkey.originsHint':
|
||
'Повні джерела через кому, напр. https://trek.example.org. Залиште порожнім, щоб використати APP_URL.',
|
||
'admin.passkey.reset': 'Скинути passkeys',
|
||
'admin.passkey.resetHint':
|
||
'Видалити всі passkeys цього користувача (напр. у разі втрати пристрою). Він зможе входити за допомогою свого пароля.',
|
||
'admin.passkey.resetConfirm': 'Видалити всі passkeys для {name}?',
|
||
'admin.passkey.resetDone': 'Видалено passkeys: {count}',
|
||
'admin.defaultSettings.mapProvider': 'Картографічний рушій',
|
||
'admin.defaultSettings.mapProviderHint':
|
||
'Карта за замовчуванням для всіх на цьому екземплярі. Кожен користувач може змінити її у власних налаштуваннях.',
|
||
'admin.defaultSettings.providerLeaflet': 'Стандартна (безкоштовна)',
|
||
'admin.defaultSettings.providerMapbox': 'Mapbox (3D)',
|
||
'admin.defaultSettings.providerMapLibre': 'MapLibre (OpenFreeMap)',
|
||
'admin.defaultSettings.mapboxToken': 'Спільний токен Mapbox',
|
||
'admin.defaultSettings.mapboxTokenHint':
|
||
'Використовується для кожного користувача, який не ввів власний токен — щоб увесь екземпляр отримав Mapbox без потреби ділитися ключем окремо. Зберігається в зашифрованому вигляді.',
|
||
'admin.defaultSettings.mapboxStyle': 'Стиль карти',
|
||
'admin.defaultSettings.mapboxStylePlaceholder': 'Виберіть стиль…',
|
||
'admin.defaultSettings.mapbox3d': '3D-будівлі та рельєф',
|
||
'admin.defaultSettings.mapboxQuality': 'Режим високої якості',
|
||
'admin.defaultSettings.cartoKey': 'Спільний ключ CARTO',
|
||
'admin.defaultSettings.cartoKeyHint':
|
||
'Використовується для кожного користувача, який не ввів власний ключ, щоб увесь екземпляр отримував плитки CARTO без водяного знака. Зберігається в зашифрованому вигляді.',
|
||
'admin.group.users': 'Users',
|
||
'admin.group.config': 'Configuration',
|
||
'admin.group.integration': 'Integrations',
|
||
'admin.group.maintenance': 'Maintenance',
|
||
'admin.invite.tripLabel': 'Додати до подорожі (необов’язково)',
|
||
'admin.invite.tripNone': 'Без подорожі',
|
||
'admin.invite.tripHint': 'Новий користувач автоматично додається до цієї подорожі, коли реєструється за посиланням.',
|
||
'admin.invite.boundTo': 'додає до {trip}',
|
||
};
|
||
export default admin;
|