From db5c4032390615ea616ddee333ee3fb5efc9eef8 Mon Sep 17 00:00:00 2001 From: Maurice <61554723+mauriceboe@users.noreply.github.com> Date: Mon, 25 May 2026 18:37:15 +0200 Subject: [PATCH] i18n: register Korean + add Ukrainian translation (#1055) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Korean translation by @ppuassi (#977) — now registered. Ukrainian by @JeffyOLOLO (#902) — lifted onto a clean branch. Both at full en.ts key parity (2258 keys). --- client/src/i18n/TranslationContext.tsx | 6 +- client/src/i18n/supportedLanguages.ts | 2 + client/src/i18n/translations/uk.ts | 2391 ++++++++++++++++++++++++ client/tests/unit/i18n/index.test.ts | 4 +- 4 files changed, 2400 insertions(+), 3 deletions(-) create mode 100644 client/src/i18n/translations/uk.ts diff --git a/client/src/i18n/TranslationContext.tsx b/client/src/i18n/TranslationContext.tsx index adf7795d..e0b61d1b 100644 --- a/client/src/i18n/TranslationContext.tsx +++ b/client/src/i18n/TranslationContext.tsx @@ -17,6 +17,8 @@ import br from './translations/br' import cs from './translations/cs' import pl from './translations/pl' import ja from './translations/ja' +import ko from './translations/ko' +import uk from './translations/uk' import { SUPPORTED_LANGUAGES, SupportedLanguageCode } from './supportedLanguages' export { SUPPORTED_LANGUAGES } @@ -25,7 +27,7 @@ type TranslationStrings = Record = { - de, en, es, fr, hu, it, tr, ru, zh, 'zh-TW': zhTw, nl, id, ar, br, cs, pl, ja, + de, en, es, fr, hu, it, tr, ru, zh, 'zh-TW': zhTw, nl, id, ar, br, cs, pl, ja, ko, uk, } // Derived from SUPPORTED_LANGUAGES — add new languages there, not here. @@ -40,7 +42,7 @@ export function getLocaleForLanguage(language: string): string { export function getIntlLanguage(language: string): string { if (language === 'br') return 'pt-BR' - return ['de', 'es', 'fr', 'hu', 'it', 'tr', 'ru', 'zh', 'zh-TW', 'nl', 'ar', 'cs', 'pl', 'id', 'ja'].includes(language) ? language : 'en' + return ['de', 'es', 'fr', 'hu', 'it', 'tr', 'ru', 'zh', 'zh-TW', 'nl', 'ar', 'cs', 'pl', 'id', 'ja', 'ko', 'uk'].includes(language) ? language : 'en' } export function isRtlLanguage(language: string): boolean { diff --git a/client/src/i18n/supportedLanguages.ts b/client/src/i18n/supportedLanguages.ts index bce41aba..e85747ab 100644 --- a/client/src/i18n/supportedLanguages.ts +++ b/client/src/i18n/supportedLanguages.ts @@ -16,6 +16,8 @@ export const SUPPORTED_LANGUAGES = [ { value: 'ar', label: 'العربية', locale: 'ar-SA' }, { value: 'id', label: 'Bahasa Indonesia', locale: 'id-ID' }, { value: 'ja', label: '日本語', locale: 'ja-JP' }, + { value: 'ko', label: '한국어', locale: 'ko-KR' }, + { value: 'uk', label: 'Українська', locale: 'uk-UA' }, ] as const export type SupportedLanguageCode = typeof SUPPORTED_LANGUAGES[number]['value'] diff --git a/client/src/i18n/translations/uk.ts b/client/src/i18n/translations/uk.ts new file mode 100644 index 00000000..433016f6 --- /dev/null +++ b/client/src/i18n/translations/uk.ts @@ -0,0 +1,2391 @@ +const uk: Record = { + // Common + 'common.save': 'Зберегти', + 'common.showMore': 'Показати більше', + 'common.showLess': 'Показати менше', + 'common.cancel': 'Скасувати', + 'common.clear': 'Очистити', + 'common.delete': 'Видалити', + 'common.edit': 'Редагувати', + 'common.add': 'Додати', + 'common.loading': 'Завантаження...', + 'common.import': 'Імпорт', + 'common.select': 'Вибрати', + 'common.selectAll': 'Вибрати все', + 'common.deselectAll': 'Зняти виділення з усіх', + 'common.error': 'Помилка', + 'common.unknownError': 'Невідома помилка', + 'common.tooManyAttempts': 'Занадто багато спроб. Спробуйте пізніше.', + 'common.back': 'Назад', + 'common.all': 'Все', + 'common.close': 'Закрити', + 'common.open': 'Відкрити', + 'common.upload': 'Завантажити', + 'common.search': 'Пошук', + 'common.confirm': 'Підтвердити', + 'common.ok': 'ОК', + 'common.yes': 'Так', + 'common.no': 'Ні', + 'common.or': 'або', + 'common.none': 'Немає', + 'common.date': 'Дата', + 'common.rename': 'Перейменувати', + 'common.discardChanges': 'Скасувати зміни', + 'common.discard': 'Скасувати', + 'common.name': 'Ім\'я', + 'common.email': 'Ел. пошта', + 'common.password': 'Пароль', + 'common.saving': 'Збереження...', + 'common.saved': 'Збережено', + 'common.expand': 'Розгорнути', + 'common.collapse': 'Згорнути', + 'trips.memberRemoved': '{username} видалений', + 'trips.memberRemoveError': 'Не вдалося видалити', + 'trips.memberAdded': '{username} доданий', + 'trips.memberAddError': 'Не вдалося додати', + 'trips.reminder': 'Нагадування', + 'trips.reminderNone': 'Немає', + 'trips.reminderDay': 'день', + 'trips.reminderDays': 'днів', + 'trips.reminderCustom': 'Інше', + 'trips.reminderDaysBefore': 'днів до від\'їзду', + 'trips.reminderDisabledHint': 'Нагадування про поїздки вимкнено. Увімкніть їх в Адмін > Налаштування > Сповіщення.', + 'common.update': 'Оновити', + 'common.change': 'Змінити', + 'common.uploading': 'Завантаження…', + 'common.backToPlanning': 'Повернутися до планування', + 'common.reset': 'Скинути', + + // Navbar + 'nav.trip': 'Поїздка', + 'nav.share': 'Поділитися', + 'nav.settings': 'Налаштування', + 'nav.admin': 'Адмін', + 'nav.logout': 'Вийти', + 'nav.lightMode': 'Світла тема', + 'nav.darkMode': 'Темна тема', + 'nav.autoMode': 'Авто', + 'nav.administrator': 'Адміністратор', + + // Dashboard + 'dashboard.title': 'Мої поїздки', + 'dashboard.subtitle.loading': 'Завантаження поїздок...', + 'dashboard.subtitle.trips': '{count} поїздок ({archived} в архіві)', + 'dashboard.subtitle.empty': 'Почніть свою першу поїздку', + 'dashboard.subtitle.activeOne': '{count} активна поїздка', + 'dashboard.subtitle.activeMany': '{count} активних поїздок', + 'dashboard.subtitle.archivedSuffix': ' · {count} в архіві', + 'dashboard.newTrip': 'Нова поїздка', + 'dashboard.gridView': 'Плитка', + 'dashboard.listView': 'Список', + 'dashboard.currency': 'Валюта', + 'dashboard.timezone': 'Часові пояси', + 'dashboard.localTime': 'Місцеве', + 'dashboard.timezoneCustomTitle': 'Свій часовий пояс', + 'dashboard.timezoneCustomLabelPlaceholder': 'Назва (необов\'язково)', + 'dashboard.timezoneCustomTzPlaceholder': 'напр. America/New_York', + 'dashboard.timezoneCustomAdd': 'Додати', + 'dashboard.timezoneCustomErrorEmpty': 'Введіть ідентифікатор часового поясу', + 'dashboard.timezoneCustomErrorInvalid': 'Невірний часовий пояс. Використовуйте формат Europe/Berlin', + 'dashboard.timezoneCustomErrorDuplicate': 'Вже додано', + 'dashboard.emptyTitle': 'Немає поїздок', + 'dashboard.emptyText': 'Створіть свою першу поїздку і почніть планувати!', + 'dashboard.emptyButton': 'Створити першу поїздку', + 'dashboard.nextTrip': 'Наступна поїздка', + 'dashboard.shared': 'Спільна', + 'dashboard.sharedBy': 'Поділився {name}', + 'dashboard.days': 'Дні', + 'dashboard.places': 'Місця', + 'dashboard.members': 'Попутники', + 'dashboard.archive': 'Архівувати', + 'dashboard.copyTrip': 'Копіювати', + 'dashboard.copySuffix': 'копія', + 'dashboard.restore': 'Відновити', + 'dashboard.archived': 'В архіві', + 'dashboard.status.ongoing': 'Триває', + 'dashboard.status.today': 'Сьогодні', + 'dashboard.status.tomorrow': 'Завтра', + 'dashboard.status.past': 'Минуло', + 'dashboard.status.daysLeft': 'залишилось {count} дн.', + 'dashboard.toast.loadError': 'Не вдалося завантажити поїздки', + 'dashboard.toast.created': 'Поїздка створена!', + 'dashboard.toast.createError': 'Не вдалося створити поїздку', + 'dashboard.toast.updated': 'Поїздка оновлена!', + 'dashboard.toast.updateError': 'Не вдалося оновити поїздку', + 'dashboard.toast.deleted': 'Поїздка видалена', + 'dashboard.toast.deleteError': 'Не вдалося видалити поїздку', + 'dashboard.toast.archived': 'Поїздка архівована', + 'dashboard.toast.archiveError': 'Не вдалося архівувати поїздку', + 'dashboard.toast.restored': 'Поїздка відновлена', + 'dashboard.toast.restoreError': 'Не вдалося відновити поїздку', + 'dashboard.toast.copied': 'Поїздка скопійована!', + 'dashboard.toast.copyError': 'Не вдалося скопіювати поїздку', + 'dashboard.confirm.copy.confirm': 'Скопіювати поїздку', + 'dashboard.confirm.copy.title': 'Скопіювати цю поїздку?', + 'dashboard.confirm.copy.will1': 'Дні, місця та призначення за днями', + 'dashboard.confirm.copy.will2': 'Проживання та бронювання', + 'dashboard.confirm.copy.will3': 'Статті бюджету та порядок категорій', + 'dashboard.confirm.copy.will4': 'Списки речей (непозначені)', + 'dashboard.confirm.copy.will5': 'Задачі (непризначені та непозначені)', + 'dashboard.confirm.copy.will6': 'Нотатки дня', + 'dashboard.confirm.copy.willCopy': 'Буде скопійовано', + 'dashboard.confirm.copy.wont1': 'Учасники та їх призначення', + 'dashboard.confirm.copy.wont2': 'Спільні нотатки, опитування та повідомлення', + 'dashboard.confirm.copy.wont3': 'Файли та фото', + 'dashboard.confirm.copy.wont4': 'Токени доступу', + 'dashboard.confirm.copy.wontCopy': 'Не буде скопійовано', + 'dashboard.confirm.delete': 'Видалити поїздку «{title}»? Всі місця та плани будуть безповоротно видалені.', + 'dashboard.editTrip': 'Редагувати поїздку', + 'dashboard.createTrip': 'Створити нову поїздку', + 'dashboard.tripTitle': 'Назва', + 'dashboard.tripTitlePlaceholder': 'напр. Літо в Японії', + 'dashboard.tripDescription': 'Опис', + 'dashboard.tripDescriptionPlaceholder': 'Про що ця поїздка?', + 'dashboard.startDate': 'Дата початку', + 'dashboard.endDate': 'Дата закінчення', + 'dashboard.dayCount': 'Кількість днів', + 'dashboard.dayCountHint': 'Скільки днів планувати, якщо дати поїздки не вказані.', + 'dashboard.noDateHint': 'Дата не вказана — буде створено 7 днів за замовчуванням. Ви можете змінити це в будь-який час.', + 'dashboard.coverImage': 'Обкладинка', + 'dashboard.addCoverImage': 'Додати обкладинку', + 'dashboard.addMembers': 'Учасники', + 'dashboard.addMember': 'Додати учасника', + 'dashboard.coverSaved': 'Обкладинка збережена', + 'dashboard.coverUploadError': 'Помилка завантаження', + 'dashboard.coverRemoveError': 'Помилка видалення', + 'dashboard.titleRequired': 'Назва обов\'язкова', + 'dashboard.endDateError': 'Дата закінчення повинна бути пізніше дати початку', + + // Settings + 'settings.title': 'Налаштування', + 'settings.subtitle': 'Налаштуйте свої персональні параметри', + 'settings.tabs.display': 'Відображення', + 'settings.tabs.map': 'Карта', + 'settings.tabs.notifications': 'Сповіщення', + 'settings.tabs.integrations': 'Інтеграції', + 'settings.tabs.account': 'Обліковий запис', + 'settings.tabs.offline': 'Офлайн', + 'settings.tabs.about': 'Про застосунок', + 'settings.map': 'Карта', + 'settings.mapTemplate': 'Шаблон карти', + 'settings.mapTemplatePlaceholder.select': 'Виберіть шаблон...', + 'settings.mapDefaultHint': 'Залиште порожнім для OpenStreetMap (за замовчуванням)', + 'settings.mapTemplatePlaceholder': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + 'settings.mapHint': 'URL-шаблон для тайлів карти', + 'settings.mapProvider': 'Провайдер карти', + 'settings.mapProviderHint': 'Застосовується до Trip Planner та Journey. Atlas завжди використовує Leaflet.', + 'settings.mapLeafletSubtitle': 'Класичні 2D, будь-які растрові тайли', + 'settings.mapMapboxSubtitle': 'Векторні тайли, 3D-будинки та рельєф', + 'settings.mapExperimental': 'Експериментально', + 'settings.mapMapboxToken': 'Токен доступу Mapbox', + 'settings.mapMapboxTokenHint': 'Публічний токен (pk.*) з', + 'settings.mapMapboxTokenLink': 'mapbox.com → Токени доступу', + 'settings.mapStyle': 'Стиль карти', + 'settings.mapStylePlaceholder': 'Виберіть стиль Mapbox', + 'settings.mapStyleHint': 'Preset або власний URL mapbox://styles/USER/ID', + 'settings.map3dBuildings': '3D-будинки та рельєф', + 'settings.map3dHint': 'Нахил + справжні 3D-будинки — працює з усіма стилями, включаючи супутник.', + 'settings.mapHighQuality': 'Режим високої якості', + 'settings.mapHighQualityHint': 'Згладжування + проекція глобуса для більш чітких країв та реалістичного вигляду світу.', + 'settings.mapHighQualityWarning': 'Може вплинути на продуктивність на слабких пристроях.', + 'settings.mapTipLabel': 'Порада:', + 'settings.mapTip': 'Затисніть праву кнопку миші та перетягніть, щоб повернути/нахилити карту. Клік середньою кнопкою — додати місце (права кнопка зарезервована для обертання).', + 'settings.latitude': 'Широта', + 'settings.longitude': 'Довгота', + 'settings.saveMap': 'Зберегти карту', + 'settings.apiKeys': 'API-ключі', + 'settings.mapsKey': 'API-ключ Google Maps', + 'settings.mapsKeyHint': 'Для пошуку місць. Потрібен Places API (New). Отримайте на console.cloud.google.com', + 'settings.weatherKey': 'API-ключ OpenWeatherMap', + 'settings.weatherKeyHint': 'Для даних про погоду. Безкоштовно на openweathermap.org/api', + 'settings.keyPlaceholder': 'Введіть ключ...', + 'settings.configured': 'Налаштовано', + 'settings.saveKeys': 'Зберегти ключі', + 'settings.display': 'Відображення', + 'settings.colorMode': 'Кольорова схема', + 'settings.light': 'Світла', + 'settings.dark': 'Темна', + 'settings.auto': 'Авто', + 'settings.language': 'Мова', + 'settings.temperature': 'Одиниця температури', + 'settings.timeFormat': 'Формат часу', + 'settings.routeCalculation': 'Розрахунок маршруту', + 'settings.blurBookingCodes': 'Приховати коди бронювання', + 'settings.notifications': 'Сповіщення', + 'settings.notifyTripInvite': 'Запрошення до поїздки', + 'settings.notifyBookingChange': 'Зміни бронювань', + 'settings.notifyTripReminder': 'Нагадування про поїздку', + 'settings.notifyTodoDue': 'Завдання до терміну', + 'settings.notifyVacayInvite': 'Запрошення об\'єднання Vacay', + 'settings.notifyPhotosShared': 'Спільні фото (Immich)', + 'settings.notifyCollabMessage': 'Повідомлення чату (Collab)', + 'settings.notifyPackingTagged': 'Список речей: призначення', + 'settings.notifyWebhook': 'Webhook-сповіщення', + 'settings.notificationsDisabled': 'Сповіщення не налаштовані. Попросіть адміністратора ввімкнути сповіщення електронною поштою або webhook.', + 'settings.notificationsActive': 'Активний канал', + 'settings.notificationsManagedByAdmin': 'Події сповіщень налаштовуються адміністратором.', + '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': 'Помилка відправки тестового листа', + 'dayplan.icsTooltip': 'Експорт календаря (ICS)', + 'share.linkTitle': 'Публічне посилання', + 'share.linkHint': 'Створіть посилання, за яким будь-хто зможе переглянути цю поїздку без входу. Тільки читання — редагувати не можна.', + 'share.createLink': 'Створити посилання', + 'share.deleteLink': 'Видалити посилання', + 'share.createError': 'Не вдалося створити посилання', + 'common.copy': 'Копіювати', + 'common.copied': 'Скопійовано', + 'share.permMap': 'Карта і план', + 'share.permBookings': 'Бронювання', + 'share.permPacking': 'Речі', + 'shared.expired': 'Посилання прострочено або недійсне', + 'shared.expiredHint': 'Це посилання на поїздку більше не активне.', + 'shared.readOnly': 'Тільки для читання', + 'shared.tabPlan': 'План', + 'shared.tabBookings': 'Бронювання', + 'shared.tabPacking': 'Багаж', + 'shared.tabBudget': 'Бюджет', + 'shared.tabChat': 'Чат', + 'shared.days': 'днів', + 'shared.places': 'місць', + 'shared.other': 'Інше', + 'shared.totalBudget': 'Загальний бюджет', + 'shared.messages': 'повідомлень', + 'shared.sharedVia': 'Поділено через', + 'shared.confirmed': 'Підтверджено', + 'shared.pending': 'Очікує', + 'share.permBudget': 'Бюджет', + 'share.permCollab': 'Чат', + 'settings.on': 'Увімк.', + 'settings.off': 'Вимк.', + 'settings.mcp.title': 'Налаштування MCP', + 'settings.mcp.endpoint': 'MCP-ендпоінт', + 'settings.mcp.clientConfig': 'Конфігурація клієнта', + 'settings.mcp.clientConfigHint': 'Замініть на API-токен зі списку нижче. Шлях до npx може потребувати налаштування для вашої системи (наприклад, C:\\PROGRA~1\\nodejs\\npx.cmd у Windows).', + 'settings.mcp.clientConfigHintOAuth': 'Замініть і на облікові дані з вищезазначеного клієнта OAuth 2.1. При першому підключенні mcp-remote відкриє браузер для завершення авторизації. Шлях до npx може потребувати налаштування для вашої системи (наприклад, C:\\PROGRA~1\\nodejs\\npx.cmd у Windows).', + 'settings.mcp.copy': 'Копіювати', + 'settings.mcp.copied': 'Скопійовано!', + 'settings.mcp.apiTokens': 'API-токени', + 'settings.mcp.createToken': 'Створити токен', + 'settings.mcp.noTokens': 'Токенів поки немає. Створіть один для підключення MCP-клієнтів.', + 'settings.mcp.tokenCreatedAt': 'Створено', + 'settings.mcp.tokenUsedAt': 'Використано', + 'settings.mcp.deleteTokenTitle': 'Видалити токен', + 'settings.mcp.deleteTokenMessage': 'Цей токен перестане працювати одразу. Будь-який MCP-клієнт, що його використовує, втратить доступ.', + 'settings.mcp.modal.createTitle': 'Створити API-токен', + 'settings.mcp.modal.tokenName': 'Назва токена', + 'settings.mcp.modal.tokenNamePlaceholder': 'наприклад Claude Desktop, Робочий ноутбук', + 'settings.mcp.modal.creating': 'Створення…', + 'settings.mcp.modal.create': 'Створити токен', + 'settings.mcp.modal.createdTitle': 'Токен створено', + 'settings.mcp.modal.createdWarning': 'Цей токен буде показано лише один раз. Скопіюйте і збережіть його зараз — відновити його не можна.', + 'settings.mcp.modal.done': 'Готово', + 'settings.mcp.toast.created': 'Токен створено', + 'settings.mcp.toast.createError': 'Не вдалося створити токен', + 'settings.mcp.toast.deleted': 'Токен видалено', + 'settings.mcp.toast.deleteError': 'Не вдалося видалити токен', + 'settings.mcp.apiTokensDeprecated': 'API-токени застаріли і будуть видалені в наступній версії. Будь ласка, використовуйте клієнти OAuth 2.1.', + 'settings.oauth.clients': 'Клієнти OAuth 2.1', + 'settings.oauth.clientsHint': 'Зареєструйте клієнтів OAuth 2.1, щоб сторонні MCP-застосунки (Claude Web, Cursor тощо) могли підключатися без статичних токенів.', + 'settings.oauth.createClient': 'Новий клієнт', + 'settings.oauth.noClients': 'Немає зареєстрованих клієнтів OAuth.', + 'settings.oauth.clientId': 'ID клієнта', + 'settings.oauth.clientSecret': 'Секрет клієнта', + 'settings.oauth.deleteClient': 'Видалити клієнта', + 'settings.oauth.deleteClientMessage': 'Цей клієнт і всі активні сесії будуть видалені назавжди. Будь-який застосунок, що його використовує, одразу втратить доступ.', + 'settings.oauth.rotateSecret': 'Оновити секрет', + 'settings.oauth.rotateSecretMessage': 'Буде згенеровано новий секрет клієнта, а всі існуючі сесії будуть негайно анульовані. Оновіть застосунок перед закриттям цього діалогу.', + 'settings.oauth.rotateSecretConfirm': 'Оновити', + 'settings.oauth.rotateSecretConfirming': 'Оновлення…', + 'settings.oauth.rotateSecretDoneTitle': 'Новий секрет згенеровано', + 'settings.oauth.rotateSecretDoneWarning': 'Цей секрет відображається лише один раз. Скопіюйте його зараз і оновіть застосунок — всі попередні сесії були анульовані.', + 'settings.oauth.activeSessions': 'Активні сесії OAuth', + 'settings.oauth.sessionScopes': 'Області доступу', + 'settings.oauth.sessionExpires': 'Закінчується', + 'settings.oauth.revoke': 'Відкликати', + 'settings.oauth.revokeSession': 'Відкликати сесію', + 'settings.oauth.revokeSessionMessage': 'Це негайно відкличе доступ для даної сесії OAuth.', + 'settings.oauth.modal.createTitle': 'Зареєструвати клієнта OAuth', + 'settings.oauth.modal.presets': 'Швидкі налаштування', + 'settings.oauth.modal.clientName': 'Назва застосунку', + 'settings.oauth.modal.clientNamePlaceholder': 'напр. Claude Web, Мій MCP-застосунок', + 'settings.oauth.modal.redirectUris': 'URI перенаправлення', + 'settings.oauth.modal.redirectUrisPlaceholder': 'https://your-app.com/callback\nhttps://your-app.com/auth', + 'settings.oauth.modal.redirectUrisHint': 'Один URI на рядок. Потрібен HTTPS (localhost виключено). Потрібне точне співпадіння.', + 'settings.oauth.modal.scopes': 'Дозволені області доступу', + 'settings.oauth.modal.scopesHint': 'list_trips і get_trip_summary завжди доступні — область не потрібна. Вони допомагають ШІ знаходити потрібні ID поїздок.', + 'settings.oauth.modal.selectAll': 'Вибрати все', + 'settings.oauth.modal.deselectAll': 'Зняти вибір', + 'settings.oauth.modal.creating': 'Реєстрація…', + 'settings.oauth.modal.create': 'Зареєструвати клієнта', + 'settings.oauth.modal.createdTitle': 'Клієнт зареєстровано', + 'settings.oauth.modal.createdWarning': 'Секрет клієнта показується лише один раз. Скопіюйте його зараз — його не можна буде відновити.', + 'settings.oauth.toast.createError': 'Не вдалося зареєструвати клієнта OAuth', + 'settings.oauth.toast.deleted': 'Клієнт OAuth видалено', + 'settings.oauth.toast.deleteError': 'Не вдалося видалити клієнта OAuth', + 'settings.oauth.toast.revoked': 'Сесію відкликано', + 'settings.oauth.toast.revokeError': 'Не вдалося відкликати сесію', + 'settings.oauth.toast.rotateError': 'Не вдалося оновити секрет клієнта', + 'settings.account': 'Обліковий запис', + 'settings.about': 'Про застосунок', + 'settings.about.reportBug': 'Повідомити про помилку', + 'settings.about.reportBugHint': 'Знайшли проблему? Повідомте нам', + 'settings.about.featureRequest': 'Запропонувати функцію', + 'settings.about.featureRequestHint': 'Запропонуйте нову функцію', + 'settings.about.wikiHint': 'Документація та керівництва', + 'settings.about.supporters.badge': 'Щомісячні спонсори', + 'settings.about.supporters.title': 'Спутники TREK', + 'settings.about.supporters.subtitle': 'Поки ти плануєш наступний маршрут, ці люди разом зі мною планують майбутнє TREK. Їхній щомісячний внесок йде безпосередньо в розробку та реальні витрачені години — щоб TREK залишався Open Source.', + 'settings.about.supporters.since': 'спонсор з {date}', + 'settings.about.supporters.tierEmpty': 'Стань першим', + 'settings.about.supporter.tier.noReturnTicket': 'No Return Ticket', + 'settings.about.supporter.tier.lostLuggageVip': 'Lost Luggage VIP', + 'settings.about.supporter.tier.businessClassDreamer': 'Business Class Dreamer', + 'settings.about.supporter.tier.budgetTraveller': 'Budget Traveller', + 'settings.about.supporter.tier.hostelBunkmate': 'Hostel Bunkmate', + 'settings.about.description': 'TREK — це self-hosted планувальник подорожей, який допомагає організувати поїздки від першої ідеї до останнього спогаду. Планування по днях, бюджет, списки речей, фото та багато іншого — все в одному місці, на вашому власному сервері.', + 'settings.about.madeWith': 'Зроблено з', + 'settings.about.madeBy': 'Морісом і зростаючою open-source спільнотою.', + 'settings.username': 'Ім\'я користувача', + 'settings.email': 'Ел. пошта', + 'settings.role': 'Роль', + 'settings.roleAdmin': 'Адміністратор', + 'settings.oidcLinked': 'Пов’язаний з', + 'settings.changePassword': 'Змінити пароль', + 'settings.mustChangePassword': 'Ви повинні змінити пароль перед продовженням. Будь ласка, встановіть новий пароль нижче.', + 'settings.currentPassword': 'Поточний пароль', + 'settings.currentPasswordRequired': 'Поточний пароль обов’язковий', + 'settings.newPassword': 'Новий пароль', + 'settings.confirmPassword': 'Підтвердіть новий пароль', + 'settings.updatePassword': 'Оновити пароль', + 'settings.passwordRequired': 'Введіть поточний та новий паролі', + 'settings.passwordTooShort': 'Пароль повинен містити не менше 8 символів', + 'settings.passwordMismatch': 'Паролі не збігаються', + 'settings.passwordWeak': 'Пароль повинен містити великі й малі літери, цифру та спеціальний символ', + 'settings.passwordChanged': 'Пароль успішно змінено', + 'settings.deleteAccount': 'Видалити акаунт', + 'settings.deleteAccountTitle': 'Видалити ваш акаунт?', + 'settings.deleteAccountWarning': 'Ваш акаунт і всі поїздки, місця та файли будуть безповоротно видалені. Цю дію неможливо скасувати.', + 'settings.deleteAccountConfirm': 'Видалити безповоротно', + 'settings.deleteBlockedTitle': 'Видалення неможливе', + 'settings.deleteBlockedMessage': 'Ви єдиний адміністратор. Призначте іншого користувача адміністратором перед видаленням свого акаунта.', + 'settings.roleUser': 'Користувач', + 'settings.saveProfile': 'Зберегти профіль', + 'settings.mfa.title': 'Двофакторна аутентифікація (2FA)', + 'settings.mfa.description': 'Додає другий крок при вході. Використовуйте додаток-аутентифікатор (Google Authenticator, Authy та ін.).', + 'settings.mfa.requiredByPolicy': 'Адміністратор вимагає двофакторної аутентифікації. Налаштуйте додаток-аутентифікатор нижче, перш ніж продовжити.', + 'settings.mfa.backupTitle': 'Резервні коди', + 'settings.mfa.backupDescription': 'Використовуйте ці одноразові коди, якщо втратите доступ до додатку-аутентифікатора.', + 'settings.mfa.backupWarning': 'Збережіть їх зараз. Кожен код можна використати лише один раз.', + 'settings.mfa.backupCopy': 'Скопіювати коди', + 'settings.mfa.backupDownload': 'Завантажити TXT', + 'settings.mfa.backupPrint': 'Друк / PDF', + 'settings.mfa.backupCopied': 'Резервні коди скопійовано', + 'settings.mfa.enabled': '2FA увімкнено для вашого акаунта.', + 'settings.mfa.disabled': '2FA не увімкнено.', + 'settings.mfa.setup': 'Налаштувати автентифікатор', + 'settings.mfa.scanQr': 'Відскануйте QR-код додатком або введіть ключ вручну.', + 'settings.mfa.secretLabel': 'Секретний ключ (ручний ввід)', + 'settings.mfa.codePlaceholder': '6-значний код', + 'settings.mfa.enable': 'Увімкнути 2FA', + 'settings.mfa.cancelSetup': 'Скасувати', + 'settings.mfa.disableTitle': 'Вимкнути 2FA', + 'settings.mfa.disableHint': 'Введіть пароль акаунта та поточний код з автентифікатора.', + 'settings.mfa.disable': 'Вимкнути 2FA', + 'settings.mfa.toastEnabled': 'Двофакторна автентифікація увімкнена', + 'settings.mfa.toastDisabled': 'Двофакторна автентифікація вимкнена', + 'settings.mfa.demoBlocked': 'Недоступно в демо-режимі', + 'settings.toast.mapSaved': 'Налаштування карти збережено', + 'settings.toast.keysSaved': 'API-ключі збережено', + 'settings.toast.displaySaved': 'Налаштування відображення збережено', + 'settings.toast.profileSaved': 'Профіль збережено', + 'settings.uploadAvatar': 'Завантажити фото профілю', + 'settings.removeAvatar': 'Видалити фото профілю', + 'settings.avatarUploaded': 'Фото профілю оновлено', + 'settings.avatarRemoved': 'Фото профілю видалено', + 'settings.avatarError': 'Помилка завантаження', + + // Login + 'login.error': 'Помилка входу. Перевірте свої облікові дані.', + 'login.tagline': 'Ваші поїздки.\nВаш план.', + 'login.description': 'Плануйте поїздки разом з інтерактивними картами, бюджетами та синхронізацією в реальному часі.', + 'login.features.maps': 'Інтерактивні карти', + 'login.features.mapsDesc': 'Google Places, маршрути та кластеризація', + 'login.features.realtime': 'Синхронізація в реальному часі', + 'login.features.realtimeDesc': 'Плануйте разом через WebSocket', + 'login.features.budget': 'Контроль бюджету', + 'login.features.budgetDesc': 'Категорії, графіки та витрати на особу', + 'login.features.collab': 'Спільна робота', + 'login.features.collabDesc': 'Багатокористувацький режим зі спільними поїздками', + 'login.features.packing': 'Списки речей', + 'login.features.packingDesc': 'Категорії, прогрес та підказки', + 'login.features.bookings': 'Бронювання', + 'login.features.bookingsDesc': 'Авіаквитки, готелі, ресторани та багато іншого', + 'login.features.files': 'Документи', + 'login.features.filesDesc': 'Завантажуйте та керуйте документами', + 'login.features.routes': 'Розумні маршрути', + 'login.features.routesDesc': 'Автооптимізація та експорт з Google Maps', + 'login.selfHosted': 'Self-hosted · Відкритий код · Ваші дані залишаються у вас', + 'login.title': 'Вхід', + 'login.subtitle': 'З поверненням', + 'login.signingIn': 'Вхід…', + 'login.signIn': 'Увійти', + 'login.createAdmin': 'Створити акаунт адміністратора', + 'login.createAdminHint': 'Налаштуйте перший акаунт адміністратора для TREK.', + 'login.setNewPassword': 'Встановити новий пароль', + 'login.setNewPasswordHint': 'Ви повинні змінити пароль, перш ніж продовжити.', + 'login.createAccount': 'Створити акаунт', + 'login.createAccountHint': 'Зареєструйте новий акаунт.', + 'login.creating': 'Створення…', + 'login.noAccount': 'Немає акаунту?', + 'login.hasAccount': 'Вже є акаунт?', + 'login.register': 'Реєстрація', + 'login.emailPlaceholder': 'ваш@email.com', + 'login.username': 'Ім’я користувача', + 'login.oidc.registrationDisabled': 'Реєстрацію вимкнено. Зверніться до адміністратора.', + 'login.oidc.noEmail': 'Провайдер не надав адресу електронної пошти.', + 'login.mfaTitle': 'Двофакторна автентифікація', + 'login.mfaSubtitle': 'Введіть 6-значний код з додатка-автентифікатора.', + 'login.mfaCodeLabel': 'Код підтвердження', + 'login.mfaCodeRequired': 'Введіть код із додатка-автентифікатора.', + 'login.mfaHint': 'Відкрийте Google Authenticator, Authy або інший TOTP-додаток.', + 'login.mfaBack': '← Назад до входу', + 'login.mfaVerify': 'Підтвердити', + 'login.invalidInviteLink': 'Недійсне або прострочене посилання-запрошення', + 'login.oidcFailed': 'Помилка входу через OIDC', + 'login.usernameRequired': 'Ім’я користувача обов’язкове', + 'login.passwordMinLength': 'Пароль має містити щонайменше 8 символів', + 'login.forgotPassword': 'Забули пароль?', + 'login.forgotPasswordTitle': 'Скидання пароля', + 'login.forgotPasswordBody': 'Введіть електронну пошту, з якою ви реєструвалися. Якщо акаунт існує — буде надіслано посилання для скидання.', + 'login.forgotPasswordSubmit': 'Надіслати посилання', + 'login.forgotPasswordSentTitle': 'Перевірте пошту', + 'login.forgotPasswordSentBody': 'Якщо акаунт існує, посилання для скидання має бути вже відправлено. Воно дійсне 60 хвилин.', + 'login.forgotPasswordSmtpHintOff': 'Зверніть увагу: адміністратор не налаштував SMTP, тому посилання для скидання буде записано в консоль сервера замість відправки електронною поштою.', + 'login.backToLogin': 'Повернутись до входу', + 'login.newPassword': 'Новий пароль', + 'login.confirmPassword': 'Підтвердіть новий пароль', + 'login.passwordsDontMatch': 'Паролі не співпадають', + 'login.mfaCode': 'Код 2FA', + 'login.resetPasswordTitle': 'Встановіть новий пароль', + 'login.resetPasswordBody': 'Виберіть надійний пароль, який ви ще не використовували. Мінімум 8 символів.', + 'login.resetPasswordMfaBody': 'Введіть код 2FA або резервний код, щоб завершити скидання.', + 'login.resetPasswordSubmit': 'Скинути пароль', + 'login.resetPasswordVerify': 'Перевірити та скинути', + 'login.resetPasswordSuccessTitle': 'Пароль оновлено', + 'login.resetPasswordSuccessBody': 'Тепер ви можете увійти з новим паролем.', + 'login.resetPasswordInvalidLink': 'Неправильне посилання для скидання', + 'login.resetPasswordInvalidLinkBody': 'Посилання відсутнє або пошкоджене. Запитайте нове, щоб продовжити.', + 'login.resetPasswordFailed': 'Скидання не вдалося. Можливо, термін дії посилання минув.', + 'login.oidc.tokenFailed': 'Автентифікація не вдалася.', + 'login.oidc.invalidState': 'Недійсна сесія. Спробуйте знову.', + 'login.demoFailed': 'Помилка демо-входу', + 'login.oidcSignIn': 'Увійти через {name}', + 'login.oidcOnly': 'Вхід за паролем вимкнено. Використайте вашого SSO-провайдера для входу.', + 'login.oidcLoggedOut': 'Ви вийшли з системи. Увійдіть знову через вашого SSO-провайдера.', + 'login.demoHint': 'Спробуйте демо — реєстрація не потрібна', + + // Register + 'register.passwordMismatch': 'Паролі не співпадають', + 'register.passwordTooShort': 'Пароль має містити щонайменше 8 символів', + 'register.failed': 'Помилка реєстрації', + 'register.getStarted': 'Почати', + 'register.subtitle': 'Створіть акаунт та почніть планувати подорожі мрії.', + 'register.feature1': 'Необмежена кількість планів подорожей', + 'register.feature2': 'Інтерактивна карта', + 'register.feature3': 'Керування місцями та категоріями', + 'register.feature4': 'Відстеження бронювань', + 'register.feature5': 'Створення списків речей', + 'register.feature6': 'Зберігання фото та файлів', + 'register.createAccount': 'Створити акаунт', + 'register.startPlanning': 'Почніть планувати свої поїздки', + 'register.minChars': 'Мін. 6 символів', + 'register.confirmPassword': 'Підтвердіть пароль', + 'register.repeatPassword': 'Повторіть пароль', + 'register.registering': 'Реєстрація...', + 'register.register': 'Зареєструватися', + 'register.hasAccount': 'Вже є акаунт?', + 'register.signIn': 'Увійти', + + // Admin + '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.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. Вхід та реєстрація за паролем будуть заблоковані.', + + // File Types + '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.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.saveError': 'Помилка збереження', + + // Addons + 'admin.tabs.addons': 'Дополнения', + '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': 'Немає доступних доповнень', + // Weather info + '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': 'Погода базується на першому місці з координатами в кожному дні. Якщо жодне місце не призначено на день, як орієнтир використовується будь-яке місце зі списку.', + + // MCP Tokens + '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-сеанси', + + // GitHub + '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.reloadHint': 'Перезавантажте сторінку через кілька секунд.', + + // Vacay addon + 'vacay.subtitle': 'Плануйте й керуйте днями відпустки', + 'vacay.settings': 'Налаштування', + 'vacay.year': 'Рік', + 'vacay.addYear': 'Додати наступний рік', + 'vacay.addPrevYear': 'Додати попередній рік', + 'vacay.removeYear': 'Видалити рік', + 'vacay.removeYearConfirm': 'Видалити {year}?', + 'vacay.removeYearHint': 'Усі записи про відпустку і корпоративні вихідні за цей рік будуть безповоротно видалені.', + 'vacay.remove': 'Видалити', + 'vacay.persons': 'Люди', + 'vacay.noPersons': 'Ніхто не доданий', + 'vacay.addPerson': 'Додати людину', + 'vacay.editPerson': 'Редагувати', + 'vacay.removePerson': 'Видалити людину', + 'vacay.removePersonConfirm': 'Видалити {name}?', + 'vacay.removePersonHint': 'Усі записи про відпустку цієї людини будуть безповоротно видалені.', + 'vacay.personName': 'Ім’я', + 'vacay.personNamePlaceholder': 'Введіть ім’я', + 'vacay.color': 'Колір', + 'vacay.add': 'Додати', + 'vacay.legend': 'Легенда', + 'vacay.publicHoliday': 'Державне свято', + 'vacay.companyHoliday': 'Корпоративний вихідний', + 'vacay.weekend': 'Вихідні', + 'vacay.modeVacation': 'Відпустка', + 'vacay.modeCompany': 'Корпоративний вихідний', + 'vacay.entitlement': 'Право на відпустку', + 'vacay.entitlementDays': 'Дні', + 'vacay.used': 'Використано', + 'vacay.remaining': 'Залишилося', + 'vacay.carriedOver': 'із {year}', + 'vacay.blockWeekends': 'Блокувати вихідні', + 'vacay.blockWeekendsHint': 'Заборонити записи про відпустку в суботу та неділю', + 'vacay.weekendDays': 'Вихідні дні', + 'vacay.mon': 'Пн', + 'vacay.tue': 'Вт', + 'vacay.wed': 'Ср', + 'vacay.thu': 'Чт', + 'vacay.fri': 'Пт', + 'vacay.sat': 'Сб', + 'vacay.sun': 'Нд', + 'vacay.publicHolidays': 'Державні свята', + 'vacay.publicHolidaysHint': 'Позначати державні свята в календарі', + 'vacay.selectCountry': 'Виберіть країну', + 'vacay.selectRegion': 'Виберіть регіон (необов’язково)', + 'vacay.companyHolidays': 'Корпоративні вихідні', + 'vacay.companyHolidaysHint': 'Дозволити позначати корпоративні вихідні', + 'vacay.companyHolidaysNoDeduct': 'Корпоративні вихідні не віднімаються від днів відпустки.', + 'vacay.weekStart': 'Тиждень починається з', + 'vacay.weekStartHint': 'Виберіть, чи тиждень починається з понеділка чи неділі', + 'vacay.carryOver': 'Переносити', + 'vacay.carryOverHint': 'Автоматично переносити залишкові дні відпустки на наступний рік', + 'vacay.sharing': 'Спільний доступ', + 'vacay.sharingHint': 'Поділіться планом відпустки з іншими користувачами TREK', + 'vacay.owner': 'Власник', + 'vacay.shareEmailPlaceholder': 'Ел. пошта користувача TREK', + 'vacay.shareSuccess': 'План успішно надано', + 'vacay.shareError': 'Не вдалося поділитися планом', + 'vacay.dissolve': 'Розділити об’єднання', + 'vacay.dissolveHint': 'Знову розділити календарі. Ваші записи будуть збережені.', + 'vacay.dissolveAction': 'Розділити', + 'vacay.dissolved': 'Календар розділено', + 'vacay.fusedWith': 'Об’єднано з', + 'vacay.you': 'ви', + 'vacay.noData': 'Немає даних', + 'vacay.changeColor': 'Змінити колір', + 'vacay.inviteUser': 'Запросити користувача', + 'vacay.inviteHint': 'Запросіть іншого користувача TREK для спільного календаря відпусток.', + 'vacay.selectUser': 'Виберіть користувача', + 'vacay.sendInvite': 'Надіслати запрошення', + 'vacay.inviteSent': 'Запрошення надіслано', + 'vacay.inviteError': 'Не вдалося надіслати запрошення', + 'vacay.pending': 'очікування', + 'vacay.noUsersAvailable': 'Немає доступних користувачів', + 'vacay.accept': 'Прийняти', + 'vacay.decline': 'Відхилити', + 'vacay.acceptFusion': 'Прийняти й об’єднати', + 'vacay.inviteTitle': 'Запит на об’єднання', + 'vacay.inviteWantsToFuse': 'хоче об’єднати календар відпусток з вами.', + 'vacay.fuseInfo1': 'Ви обидва бачитимете всі записи про відпустки в одному спільному календарі.', + 'vacay.fuseInfo2': 'Обидві сторони можуть створювати та редагувати записи одна для одної.', + 'vacay.fuseInfo3': 'Обидві сторони можуть видаляти записи та змінювати право на відпустку.', + 'vacay.fuseInfo4': 'Налаштування, такі як свята та корпоративні вихідні, стають спільними.', + 'vacay.fuseInfo5': 'Об’єднання можна скасувати будь-коли з будь-якого боку. Ваші записи будуть збережені.', + 'vacay.addCalendar': 'Добавить календарь', + 'vacay.calendarColor': 'Колір', + 'vacay.calendarLabel': 'Назва', + 'vacay.noCalendars': 'Немає календарів', + 'nav.myTrips': 'Мої поїздки', + + // Atlas addon + 'atlas.subtitle': 'Ваш слід подорожей по всьому світу', + 'atlas.countries': 'Країни', + 'atlas.trips': 'Подорожі', + 'atlas.places': 'Місця', + 'atlas.days': 'Дні', + 'atlas.visitedCountries': 'Відвідані країни', + 'atlas.cities': 'Міста', + 'atlas.noData': 'Даних про подорожі поки немає', + 'atlas.noDataHint': 'Створіть подорож і додайте місця, щоб побачити карту світу', + 'atlas.lastTrip': 'Остання подорож', + 'atlas.nextTrip': 'Наступна подорож', + 'atlas.daysLeft': 'днів залишилося', + 'atlas.streak': 'Серія', + 'atlas.year': 'рік', + 'atlas.years': 'років', + 'atlas.yearInRow': 'рік підряд', + 'atlas.yearsInRow': 'років підряд', + 'atlas.tripIn': 'подорожі до', + 'atlas.tripsIn': 'подорожей до', + 'atlas.since': 'з', + 'atlas.europe': 'Європа', + 'atlas.asia': 'Азія', + 'atlas.northAmerica': 'Пн. Америка', + 'atlas.southAmerica': 'Пд. Америка', + 'atlas.africa': 'Африка', + 'atlas.oceania': 'Океанія', + 'atlas.other': 'Інше', + 'atlas.firstVisit': 'Перша поїздка', + 'atlas.lastVisitLabel': 'Остання поїздка', + 'atlas.tripSingular': 'Поїздка', + 'atlas.tripPlural': 'Поїздки', + 'atlas.placeVisited': 'Відвідане місце', + 'atlas.placesVisited': 'Відвідані місця', + 'atlas.statsTab': 'Статистика', + 'atlas.bucketTab': 'Список бажань', + 'atlas.addBucket': 'Додати до списку бажань', + 'atlas.bucketNamePlaceholder': 'Місце або напрямок...', + 'atlas.bucketNotesPlaceholder': 'Нотатки (необов’язково)', + 'atlas.bucketEmpty': 'Ваш список бажань порожній', + 'atlas.bucketEmptyHint': 'Додайте місця, які мрієте відвідати', + 'atlas.unmark': 'Видалити', + 'atlas.confirmMark': 'Позначити цю країну як відвідану?', + 'atlas.confirmUnmark': 'Видалити цю країну зі списку відвіданих?', + 'atlas.confirmUnmarkRegion': 'Видалити цей регіон зі списку відвіданих?', + 'atlas.markVisited': 'Позначити як відвідану', + 'atlas.markVisitedHint': 'Додати цю країну до списку відвіданих', + 'atlas.markRegionVisitedHint': 'Додати цей регіон до списку відвіданих', + 'atlas.addToBucket': 'До списку бажань', + 'atlas.addPoi': 'Додати місце', + 'atlas.searchCountry': 'Пошук країни...', + 'atlas.month': 'Місяць', + 'atlas.addToBucketHint': 'Зберегти як місце для відвідування', + 'atlas.bucketWhen': 'Коли ви плануєте поїхати?', + + // Trip Planner + 'trip.tabs.plan': 'План', + 'trip.tabs.transports': 'Транспорт', + 'trip.tabs.reservations': 'Бронювання', + 'trip.tabs.reservationsShort': 'Броні', + 'trip.tabs.packing': 'Список речей', + 'trip.tabs.packingShort': 'Речі', + 'trip.tabs.lists': 'Списки', + 'trip.tabs.listsShort': 'Списки', + 'trip.tabs.budget': 'Бюджет', + 'trip.tabs.files': 'Файли', + 'trip.loading': 'Завантаження поїздки...', + 'trip.loadingPhotos': 'Завантаження фото місць...', + 'trip.mobilePlan': 'План', + 'trip.mobilePlaces': 'Місця', + 'trip.toast.placeUpdated': 'Місце оновлено', + 'trip.toast.placeAdded': 'Місце додано', + 'trip.toast.placeDeleted': 'Місце видалено', + 'trip.toast.selectDay': 'Спочатку виберіть день', + 'trip.toast.assignedToDay': 'Місце призначено на день', + 'trip.toast.reorderError': 'Помилка зміни порядку', + 'trip.toast.reservationUpdated': 'Бронювання оновлено', + 'trip.toast.reservationAdded': 'Бронювання додано', + 'trip.toast.deleted': 'Видалено', + 'trip.confirm.deletePlace': 'Ви впевнені, що хочете видалити це місце?', + 'trip.confirm.deletePlaces': 'Видалити {count} місць?', + 'trip.toast.placesDeleted': '{count} місць видалено', + + // Day Plan Sidebar + 'dayplan.emptyDay': 'На цей день місць не заплановано', + 'dayplan.addNote': 'Додати нотатку', + 'dayplan.editNote': 'Редагувати нотатку', + 'dayplan.noteAdd': 'Додати нотатку', + 'dayplan.noteEdit': 'Редагувати нотатку', + 'dayplan.noteTitle': 'Нотатка', + 'dayplan.noteSubtitle': 'Нотатка на день', + 'dayplan.collapseAll': 'Згорнути всі дні', + 'dayplan.expandAll': 'Розгорнути всі дні', + 'dayplan.totalCost': 'Загальна вартість', + 'dayplan.days': 'Дни', + 'dayplan.dayN': 'День {n}', + 'dayplan.calculating': 'Розрахунок...', + 'dayplan.route': 'Маршрут', + 'dayplan.optimize': 'Оптимізувати', + 'dayplan.optimized': 'Маршрут оптимізовано', + 'dayplan.routeError': 'Не вдалося розрахувати маршрут', + 'dayplan.toast.needTwoPlaces': 'Для оптимизации маршрута нужно минимум два места', + 'dayplan.toast.routeOptimized': 'Маршрут оптимизирован', + 'dayplan.toast.noGeoPlaces': 'Не знайдено місць з координатами для розрахунку маршруту', + 'dayplan.confirmed': 'Подтверждено', + 'dayplan.pendingRes': 'Ожидание', + 'dayplan.pdf': 'PDF', + 'dayplan.pdfTooltip': 'Експортувати план дня в PDF', + 'dayplan.pdfError': 'Помилка експорту PDF', + 'dayplan.cannotReorderTransport': 'Бронювання з фіксованим часом не можна переміщувати', + 'dayplan.confirmRemoveTimeTitle': 'Видалити час?', + 'dayplan.confirmRemoveTimeBody': 'У цього місця фіксований час ({time}). При переміщенні час буде видалено, і стане доступне вільне сортування.', + 'dayplan.confirmRemoveTimeAction': 'Видалити час і перемістити', + 'dayplan.cannotDropOnTimed': 'Елементи не можна розміщувати між записами з фіксованим часом', + 'dayplan.cannotBreakChronology': 'Це порушить хронологічний порядок запланованих елементів і бронювань', + + // Places Sidebar + 'places.addPlace': 'Додати місце/активність', + 'places.importFile': 'Імпортувати файл', + 'places.sidebarDrop': 'Відпустіть для імпорту', + 'places.importFileHint': 'Імпортуйте файли .gpx, .kml або .kmz із інструментів, таких як Google My Maps, Google Earth або GPS-трекер.', + 'places.importFileDropHere': 'Натисніть, щоб вибрати файл, або перетягніть його сюди', + 'places.importFileDropActive': 'Відпустіть файл для вибору', + 'places.importFileUnsupported': 'Непідтримуваний тип файлу. Використовуйте .gpx, .kml або .kmz.', + 'places.importFileTooLarge': 'Файл занадто великий. Максимальний розмір завантаження — {maxMb} МБ.', + 'places.importFileError': 'Помилка імпорту', + 'places.importAllSkipped': 'Усі місця вже були в подорожі.', + 'places.gpxImported': '{count} місць імпортовано з GPX', + 'places.gpxImportTypes': 'Що імпортувати?', + 'places.gpxImportWaypoints': 'Путеві точки', + 'places.gpxImportRoutes': 'Маршрути', + 'places.gpxImportTracks': 'Треки (з геометрією маршруту)', + 'places.gpxImportNoneSelected': 'Оберіть щонайменше один тип для імпорту.', + 'places.kmlImportTypes': 'Що ви хочете імпортувати?', + 'places.kmlImportPoints': 'Точки (Placemark)', + 'places.kmlImportPaths': 'Маршрути (LineStrings)', + 'places.kmlImportNoneSelected': 'Виберіть щонайменше один тип.', + 'places.selectionCount': '{count} вибрано', + 'places.deleteSelected': 'Видалити вибране', + 'places.kmlKmzImported': '{count} місць імпортовано з KMZ/KML', + 'places.urlResolved': 'Місце імпортовано з URL', + 'places.importList': 'Імпорт списку', + 'places.kmlKmzSummaryValues': 'Позначки: {total} • Імпортовано: {created} • Пропущено: {skipped}', + 'places.importGoogleList': 'Список Google', + 'places.importNaverList': 'Список Naver', + 'places.googleListHint': 'Вставте посилання на спільний список Google Maps для імпорту всіх місць.', + 'places.googleListImported': '{count} місць імпортовано з "{list}"', + 'places.googleListError': 'Не вдалося імпортувати список Google Maps', + 'places.naverListHint': 'Вставте посилання на спільний список Naver Maps для імпорту всіх місць.', + 'places.naverListImported': '{count} місць імпортовано з "{list}"', + 'places.naverListError': 'Не вдалося імпортувати список Naver Maps', + 'places.viewDetails': 'Деталі', + 'places.assignToDay': 'Додати на який день?', + 'places.all': 'Усі', + 'places.unplanned': 'Незаплановані', + 'places.filterTracks': 'Треки', + 'places.search': 'Пошук місць...', + 'places.allCategories': 'Всі категорії', + 'places.categoriesSelected': 'категорій', + 'places.clearFilter': 'Скинути фільтр', + 'places.count': '{count} місць', + 'places.countSingular': '1 місце', + 'places.allPlanned': 'Усі місця заплановані', + 'places.noneFound': 'Місця не знайдені', + 'places.editPlace': 'Редагувати місце', + 'places.formName': 'Назва', + 'places.formNamePlaceholder': 'наприклад, Ейфелева вежа', + 'places.formDescription': 'Опис', + 'places.formDescriptionPlaceholder': 'Короткий опис...', + 'places.formAddress': 'Адреса', + 'places.formAddressPlaceholder': 'Вулиця, місто, країна', + 'places.formLat': 'Широта (наприклад, 48.8566)', + 'places.formLng': 'Довгота (наприклад, 2.3522)', + 'places.formCategory': 'Категорія', + 'places.noCategory': 'Без категорії', + 'places.categoryNamePlaceholder': 'Назва категорії', + 'places.formTime': 'Час', + 'places.startTime': 'Початок', + 'places.endTime': 'Кінець', + 'places.endTimeBeforeStart': 'Час закінчення раніше за час початку', + 'places.timeCollision': 'Перетин за часом із:', + 'places.formWebsite': 'Веб-сайт', + 'places.formNotes': 'Нотатки', + 'places.formNotesPlaceholder': 'Особисті нотатки...', + 'places.formReservation': 'Бронювання', + 'places.reservationNotesPlaceholder': 'Нотатки про бронювання, номер підтвердження...', + 'places.mapsSearchPlaceholder': 'Пошук місць...', + 'places.mapsSearchError': 'Помилка пошуку місць.', + 'places.loadingDetails': 'Завантаження даних про місце…', + 'places.osmHint': 'Пошук через OpenStreetMap (без фото, годин роботи та рейтингів). Додайте API-ключ Google у налаштуваннях для повної інформації.', + 'places.osmActive': 'Пошук через OpenStreetMap (без фото, рейтингів та годин роботи). Додайте API-ключ Google у налаштуваннях для розширених даних.', + 'places.categoryCreateError': 'Не вдалося створити категорію', + 'places.nameRequired': 'Введіть назву', + 'places.saveError': 'Помилка збереження', + // Place Inspector + 'inspector.opened': 'Відкрито', + 'inspector.closed': 'Закрито', + 'inspector.openingHours': 'Години роботи', + 'inspector.showHours': 'Показати години роботи', + 'inspector.files': 'Файли', + 'inspector.filesCount': '{count} файлів', + 'inspector.removeFromDay': 'Прибрати з дня', + 'inspector.remove': 'Видалити', + 'inspector.addToDay': 'Додати до дня', + 'inspector.confirmedRes': 'Підтверджене бронювання', + 'inspector.pendingRes': 'Очікуване бронювання', + 'inspector.google': 'Відкрити в Google Maps', + 'inspector.website': 'Відкрити сайт', + 'inspector.addRes': 'Бронювання', + 'inspector.editRes': 'Редагувати бронювання', + 'inspector.participants': 'Учасники', + 'inspector.trackStats': 'Дані маршруту', + + // Reservations + 'reservations.title': 'Бронювання', + 'reservations.empty': 'Поки немає бронювань', + 'reservations.emptyHint': 'Додайте бронювання на авіаквитки, готелі та інше', + 'reservations.add': 'Додати бронювання', + 'reservations.addManual': 'Ручне бронювання', + 'reservations.placeHint': 'Порада: бронювання краще створювати безпосередньо з місця, щоб пов’язати їх з планом дня.', + 'reservations.confirmed': 'Підтверджено', + 'reservations.pending': 'Очікування', + 'reservations.summary': '{confirmed} підтвр., {pending} очікувань', + 'reservations.fromPlan': 'З плану', + 'reservations.showFiles': 'Показати файли', + 'reservations.editTitle': 'Редагувати бронювання', + 'reservations.status': 'Статус', + 'reservations.datetime': 'Дата і час', + 'reservations.startTime': 'Час початку', + 'reservations.endTime': 'Час закінчення', + 'reservations.date': 'Дата', + 'reservations.time': 'Час', + 'reservations.timeAlt': 'Час (альтернативний, напр. 19:30)', + 'reservations.notes': 'Нотатки', + 'reservations.notesPlaceholder': 'Додаткові нотатки...', + 'reservations.meta.airline': 'Авіакомпанія', + 'reservations.meta.flightNumber': 'Номер рейсу', + 'reservations.meta.from': 'Звідки', + 'reservations.meta.to': 'Куди', + 'reservations.needsReview': 'Перевірити', + 'reservations.needsReviewHint': 'Аеропорт не вдалося визначити автоматично — підтвердіть місцезнаходження.', + 'reservations.searchLocation': 'Шукати станцію, порт, адресу...', + 'airport.searchPlaceholder': 'Код аеропорту або місто (наприклад, FRA)', + 'map.connections': 'Сполучення', + 'map.showConnections': 'Показати маршрути бронювань', + 'map.hideConnections': 'Приховати маршрути бронювань', + 'settings.bookingLabels': 'Підписи маршрутів бронювань', + 'settings.bookingLabelsHint': 'Показує назви станцій / аеропортів на карті. Якщо вимкнено, показується лише значок.', + 'reservations.meta.trainNumber': 'Номер поїзда', + 'reservations.meta.platform': 'Платформа', + 'reservations.meta.seat': 'Місце', + 'reservations.meta.checkIn': 'Заїзд', + 'reservations.meta.checkInUntil': 'Заселення до', + 'reservations.meta.checkOut': 'Виїзд', + 'reservations.meta.linkAccommodation': 'Житло', + 'reservations.meta.pickAccommodation': 'Прив’язати до житла', + 'reservations.meta.noAccommodation': 'Ні', + 'reservations.meta.hotelPlace': 'Житло', + 'reservations.meta.pickHotel': 'Оберіть житло', + 'reservations.meta.fromDay': 'З', + 'reservations.meta.toDay': 'По', + 'reservations.meta.selectDay': 'Оберіть день', + 'reservations.type.flight': 'Авіаквиток', + 'reservations.type.hotel': 'Житло', + 'reservations.type.restaurant': 'Ресторан', + 'reservations.type.train': 'Поїзд', + 'reservations.type.car': 'Автомобіль', + 'reservations.type.cruise': 'Круїз', + 'reservations.type.event': 'Заходи', + 'reservations.type.tour': 'Екскурсія', + 'reservations.type.other': 'Інше', + 'reservations.confirm.delete': 'Ви впевнені, що хочете видалити бронювання «{name}»?', + 'reservations.confirm.deleteTitle': 'Видалити бронювання?', + 'reservations.confirm.deleteBody': '«{name}» буде видалено назавжди.', + 'reservations.toast.updated': 'Бронювання оновлено', + 'reservations.toast.removed': 'Бронювання видалено', + 'reservations.toast.fileUploaded': 'Файл завантажено', + 'reservations.toast.uploadError': 'Помилка завантаження', + 'reservations.newTitle': 'Нове бронювання', + 'reservations.bookingType': 'Тип бронювання', + 'reservations.titleLabel': 'Назва', + 'reservations.titlePlaceholder': 'наприклад, Lufthansa LH123, Hotel Adlon, ...', + 'reservations.locationAddress': 'Місцезнаходження / Адреса', + 'reservations.locationPlaceholder': 'Адреса, аеропорт, готель...', + 'reservations.confirmationCode': 'Код бронювання', + 'reservations.confirmationPlaceholder': 'наприклад, ABC12345', + 'reservations.day': 'День', + 'reservations.noDay': 'Без дня', + 'reservations.place': 'Місце', + 'reservations.noPlace': 'Без місця', + 'reservations.pendingSave': 'буде збережено…', + 'reservations.uploading': 'Завантаження...', + 'reservations.attachFile': 'Прикріпити файл', + 'reservations.linkExisting': 'Прив’язати існуючий файл', + 'reservations.toast.saveError': 'Помилка збереження', + 'reservations.toast.updateError': 'Помилка оновлення', + 'reservations.toast.deleteError': 'Помилка видалення', + 'reservations.confirm.remove': 'Видалити бронювання для «{name}»?', + 'reservations.linkAssignment': 'Прив’язати до призначення дня', + 'reservations.pickAssignment': 'Оберіть призначення з вашого плану...', + 'reservations.noAssignment': 'Без прив’язки (самостійно)', + 'reservations.price': 'Ціна', + 'reservations.budgetCategory': 'Категорія бюджету', + 'reservations.budgetCategoryPlaceholder': 'наприклад, Транспорт, Проживання', + 'reservations.budgetCategoryAuto': 'Авто (за типом бронювання)', + 'reservations.budgetHint': 'При збереженні буде автоматично створено запис бюджету.', + 'reservations.departureDate': 'Виліт', + 'reservations.arrivalDate': 'Приліт', + 'reservations.departureTime': 'Час вильоту', + 'reservations.arrivalTime': 'Час прильоту', + 'reservations.pickupDate': 'Отримання', + 'reservations.returnDate': 'Повернення', + 'reservations.pickupTime': 'Час отримання', + 'reservations.returnTime': 'Час повернення', + 'reservations.endDate': 'Дата закінчення', + 'reservations.meta.departureTimezone': 'TZ вильоту', + 'reservations.meta.arrivalTimezone': 'TZ прильоту', + 'reservations.span.departure': 'Виліт', + 'reservations.span.arrival': 'Приліт', + 'reservations.span.inTransit': 'У дорозі', + 'reservations.span.pickup': 'Отримання', + 'reservations.span.return': 'Повернення', + 'reservations.span.active': 'Активно', + 'reservations.span.start': 'Початок', + 'reservations.span.end': 'Кінець', + 'reservations.span.ongoing': 'Триває', + 'reservations.validation.endBeforeStart': 'Дата/час закінчення повинен бути пізніше дати/часу початку', + 'reservations.addBooking': 'Добавить бронирование', + + // Budget + 'budget.title': 'Бюджет', + 'budget.exportCsv': 'Експорт CSV', + 'budget.emptyTitle': 'Бюджет ще не створено', + 'budget.emptyText': 'Створіть категорії й записи для планування бюджету поїздки', + 'budget.emptyPlaceholder': 'Введіть назву категорії...', + 'budget.createCategory': 'Створити категорію', + 'budget.category': 'Категорія', + 'budget.categoryName': 'Назва категорії', + 'budget.table.name': 'Назва', + 'budget.table.total': 'Всього', + 'budget.table.persons': 'Осіб', + 'budget.table.days': 'Днів', + 'budget.table.perPerson': 'На особу', + 'budget.table.perDay': 'На день', + 'budget.table.perPersonDay': 'Ос./день', + 'budget.table.note': 'Нотатка', + 'budget.table.date': 'Дата', + 'budget.newEntry': 'Новий запис', + 'budget.defaultEntry': 'Новий запис', + 'budget.defaultCategory': 'Нова категорія', + 'budget.total': 'Всього', + 'budget.totalBudget': 'Загальний бюджет', + 'budget.byCategory': 'За категоріями', + 'budget.editTooltip': 'Натисніть для редагування', + 'budget.linkedToReservation': 'Пов’язано з бронюванням — редагуйте назву там', + 'budget.confirm.deleteCategory': 'Ви впевнені, що хочете видалити категорію «{name}» з {count} записами?', + 'budget.deleteCategory': 'Видалити категорію', + 'budget.perPerson': 'На особу', + 'budget.paid': 'Оплачено', + 'budget.open': 'Не оплачено', + 'budget.noMembers': 'Учасники не призначені', + 'budget.settlement': 'Взаєморозрахунок', + 'budget.settlementInfo': 'Натисніть на аватар учасника в рядку бюджету, щоб відзначити його зеленим — це означає, що він заплатив. Взаєморозрахунок покаже, хто кому і скільки винен.', + 'budget.netBalances': 'Чисті баланси', + + // Files + 'files.title': 'Файли', + 'files.pageTitle': 'Файли та документи', + 'files.subtitle': '{count} файлів для {trip}', + 'files.download': 'Завантажити', + 'files.openError': 'Не вдалося відкрити файл', + 'files.downloadPdf': 'Завантажити PDF', + 'files.count': '{count} файлів', + 'files.countSingular': '1 файл', + 'files.uploaded': '{count} завантажено', + 'files.uploadError': 'Помилка завантаження', + 'files.dropzone': 'Перетягніть файли сюди', + 'files.dropzoneHint': 'або натисніть для вибору', + 'files.allowedTypes': 'Зображення, PDF, DOC, DOCX, XLS, XLSX, TXT, CSV · Макс. 50 МБ', + 'files.uploading': 'Завантаження...', + 'files.filterAll': 'Усі', + 'files.filterPdf': 'PDF', + 'files.filterImages': 'Зображення', + 'files.filterDocs': 'Документи', + 'files.filterCollab': 'Нотатки Collab', + 'files.sourceCollab': 'З нотаток Collab', + 'files.empty': 'Файлів поки немає', + 'files.emptyHint': 'Завантажте файли, щоб прикріпити їх до поїздки', + 'files.openTab': 'Відкрити в новій вкладці', + 'files.confirm.delete': 'Ви впевнені, що хочете видалити цей файл?', + 'files.toast.deleted': 'Файл видалено', + 'files.toast.deleteError': 'Не вдалося видалити файл', + 'files.sourcePlan': 'План дня', + 'files.sourceBooking': 'Бронювання', + 'files.attach': 'Прикріпити', + 'files.pasteHint': 'Також можна вставити зображення з буфера обміну (Ctrl+V)', + 'files.trash': 'Кошик', + 'files.trashEmpty': 'Кошик порожній', + 'files.emptyTrash': 'Очистити кошик', + 'files.restore': 'Відновити', + 'files.star': 'У фаворити', + 'files.unstar': 'Зняти з фаворитів', + 'files.assign': 'Призначити', + 'files.assignTitle': 'Призначити файл', + 'files.assignPlace': 'Місце', + 'files.assignBooking': 'Бронювання', + 'files.unassigned': 'Не призначено', + 'files.unlink': 'Видалити зв’язок', + 'files.toast.trashed': 'Переміщено до кошика', + 'files.toast.restored': 'Файл відновлено', + 'files.toast.trashEmptied': 'Кошик очищено', + 'files.toast.assigned': 'Файл призначено', + 'files.toast.assignError': 'Помилка призначення', + 'files.toast.restoreError': 'Помилка відновлення', + 'files.confirm.permanentDelete': 'Безповоротно видалити цей файл? Цю дію неможливо скасувати.', + 'files.confirm.emptyTrash': 'Безповоротно видалити всі файли з кошика? Цю дію неможливо скасувати.', + 'files.noteLabel': 'Нотатка', + 'files.notePlaceholder': 'Додати нотатку...', + + // Packing + 'packing.title': 'Список речей', + 'packing.empty': 'Список речей порожній', + 'packing.import': 'Імпорт', + 'packing.importTitle': 'Імпорт списку речей', + 'packing.importHint': 'Один предмет у рядок. Категорію та кількість — через кому, крапку з комою або табуляцію: Назва, Категорія, Кількість', + 'packing.importPlaceholder': 'Зубна щітка\nСонцезахисний крем, Гігієна\nФутболки, Одяг, 5\nПаспорт, Документи', + 'packing.importCsv': 'Завантажити CSV/TXT', + 'packing.importAction': 'Імпортувати {count}', + 'packing.importSuccess': '{count} предметів імпортовано', + 'packing.importError': 'Помилка імпорту', + 'packing.importEmpty': 'Немає предметів для імпорту', + 'packing.progress': '{packed} з {total} зібрано ({percent}%)', + 'packing.clearChecked': 'Видалити {count} позначених', + 'packing.clearCheckedShort': 'Видалити {count}', + 'packing.suggestions': 'Підказки', + 'packing.suggestionsTitle': 'Додати підказки', + 'packing.allSuggested': 'Усі підказки додано', + 'packing.allPacked': 'Усе зібрано!', + 'packing.addPlaceholder': 'Додати річ...', + 'packing.categoryPlaceholder': 'Категорія...', + 'packing.filterAll': 'Усі', + 'packing.filterOpen': 'Не зібрано', + 'packing.filterDone': 'Зібрано', + 'packing.emptyTitle': 'Список речей порожній', + 'packing.emptyHint': 'Додайте речі або використайте підказки', + 'packing.emptyFiltered': 'Немає речей, що відповідають фільтру', + 'packing.menuRename': 'Перейменувати', + 'packing.menuCheckAll': 'Позначити все', + 'packing.menuUncheckAll': 'Зняти позначки', + 'packing.menuDeleteCat': 'Видалити категорію', + 'packing.addItem': 'Додати річ', + 'packing.addItemPlaceholder': 'Назва...', + 'packing.addCategory': 'Додати категорію', + 'packing.newCategoryPlaceholder': 'Назва категорії (наприклад, Одяг)', + 'packing.applyTemplate': 'Застосувати шаблон', + 'packing.template': 'Шаблон', + 'packing.templateApplied': '{count} речей додано з шаблону', + 'packing.templateError': 'Помилка застосування шаблону', + 'packing.saveAsTemplate': 'Зберегти як шаблон', + 'packing.templateName': 'Назва шаблону', + 'packing.templateSaved': 'Список речей збережено як шаблон', + 'packing.noMembers': 'Немає учасників', + 'packing.bags': 'Багаж', + 'packing.noBag': 'Не призначено', + 'packing.totalWeight': 'Загальна вага', + 'packing.bagName': 'Назва...', + 'packing.addBag': 'Додати багаж', + 'packing.changeCategory': 'Змінити категорію', + 'packing.confirm.clearChecked': 'Ви впевнені, що хочете видалити {count} позначених речей?', + 'packing.confirm.deleteCat': 'Ви впевнені, що хочете видалити категорію «{name}» з {count} речами?', + 'packing.defaultCategory': 'Інше', + 'packing.toast.saveError': 'Помилка збереження', + 'packing.toast.deleteError': 'Помилка видалення', + 'packing.toast.renameError': 'Помилка перейменування', + 'packing.toast.addError': 'Помилка додавання', + + // Packing suggestions + 'packing.suggestions.items': [ + { name: 'Паспорт', category: 'Документи' }, + { name: 'Посвідчення особи', category: 'Документи' }, + { name: 'Страхування', category: 'Документи' }, + { name: 'Авіаквитки', category: 'Документи' }, + { name: 'Банківська картка', category: 'Фінанси' }, + { name: 'Готівка', category: 'Фінанси' }, + { name: 'Віза', category: 'Документи' }, + { name: 'Футболки', category: 'Одяг' }, + { name: 'Штани', category: 'Одяг' }, + { name: 'Нижня білизна', category: 'Одяг' }, + { name: 'Шкарпетки', category: 'Одяг' }, + { name: 'Куртка', category: 'Одяг' }, + { name: 'Піжама', category: 'Одяг' }, + { name: 'Купальник', category: 'Одяг' }, + { name: 'Дощовик', category: 'Одяг' }, + { name: 'Зручне взуття', category: 'Одяг' }, + { name: 'Зубна щітка', category: 'Гігієна' }, + { name: 'Зубна паста', category: 'Гігієна' }, + { name: 'Шампунь', category: 'Гігієна' }, + { name: 'Дезодорант', category: 'Гігієна' }, + { name: 'Сонцезахисний крем', category: 'Гігієна' }, + { name: 'Пасок', category: 'Гігієна' }, + { name: 'Зарядний пристрій', category: 'Електроніка' }, + { name: 'Зовнішній акумулятор', category: 'Електроніка' }, + { name: 'Навушники', category: 'Електроніка' }, + { name: 'Адаптер для розеток', category: 'Електроніка' }, + { name: 'Фотоапарат', category: 'Електроніка' }, + { name: 'Знеболювальні', category: 'Здоров’я' }, + { name: 'Пластирі', category: 'Здоров’я' }, + { name: 'Антисептик', category: 'Здоров’я' }, + ], + + // Members / Sharing + 'members.shareTrip': 'Поділитися поїздкою', + 'members.inviteUser': 'Запросити користувача', + 'members.selectUser': 'Оберіть користувача…', + 'members.invite': 'Запросити', + 'members.allHaveAccess': 'У всіх користувачів вже є доступ.', + 'members.access': 'Доступ', + 'members.person': 'особа', + 'members.persons': 'осіб', + 'members.you': 'ви', + 'members.owner': 'Власник', + 'members.leaveTrip': 'Покинути поїздку', + 'members.removeAccess': 'Відкликати доступ', + 'members.confirmLeave': 'Покинути поїздку? Ви втратите доступ.', + 'members.confirmRemove': 'Відкликати доступ у цього користувача?', + 'members.loadError': 'Не вдалося завантажити учасників', + 'members.added': 'додано', + 'members.addError': 'Помилка додавання', + 'members.removed': 'Учасник видалений', + 'members.removeError': 'Помилка видалення', + + // Categories (Admin) + 'categories.title': 'Категорії', + 'categories.subtitle': 'Управління категоріями місць', + 'categories.new': 'Нова категорія', + 'categories.empty': 'Категорій поки немає', + 'categories.namePlaceholder': 'Назва категорії', + 'categories.icon': 'Іконка', + 'categories.color': 'Колір', + 'categories.customColor': 'Вибрати свій колір', + 'categories.preview': 'Попередній перегляд', + 'categories.defaultName': 'Категорія', + 'categories.update': 'Оновити', + 'categories.create': 'Створити', + 'categories.confirm.delete': 'Видалити категорію? Місця в цій категорії не будуть видалені.', + 'categories.toast.loadError': 'Не вдалося завантажити категорії', + 'categories.toast.nameRequired': 'Введіть назву', + 'categories.toast.updated': 'Категорію оновлено', + 'categories.toast.created': 'Категорію створено', + 'categories.toast.saveError': 'Помилка збереження', + 'categories.toast.deleted': 'Категорію видалено', + 'categories.toast.deleteError': 'Помилка видалення', + + // Backup (Admin) + 'backup.title': 'Резервна копія', + 'backup.subtitle': 'База даних та всі завантажені файли', + 'backup.refresh': 'Оновити', + 'backup.upload': 'Завантажити копію', + 'backup.uploading': 'Завантаження…', + 'backup.create': 'Створити копію', + 'backup.creating': 'Створення…', + 'backup.empty': 'Резервних копій немає', + 'backup.createFirst': 'Створити першу копію', + 'backup.download': 'Завантажити', + 'backup.restore': 'Відновити', + 'backup.confirm.restore': 'Відновити копію «{name}»?\n\nУсі поточні дані будуть замінені даними з копії.', + 'backup.confirm.uploadRestore': 'Завантажити та відновити файл копії «{name}»?\n\nУсі поточні дані будуть перезаписані.', + 'backup.confirm.delete': 'Видалити копію «{name}»?', + 'backup.toast.loadError': 'Не вдалося завантажити резервні копії', + 'backup.toast.created': 'Резервну копію створено', + 'backup.toast.createError': 'Не вдалося створити резервну копію', + 'backup.toast.restored': 'Копію відновлено. Сторінка перезавантажиться…', + 'backup.toast.restoreError': 'Помилка відновлення', + 'backup.toast.uploadError': 'Помилка завантаження', + 'backup.toast.deleted': 'Резервну копію видалено', + 'backup.toast.deleteError': 'Помилка видалення', + 'backup.toast.downloadError': 'Помилка завантаження', + 'backup.toast.settingsSaved': 'Налаштування автокопіювання збережено', + 'backup.toast.settingsError': 'Не вдалося зберегти налаштування', + 'backup.auto.title': 'Автокопіювання', + 'backup.auto.subtitle': 'Автоматичне резервне копіювання за розкладом', + 'backup.auto.enable': 'Увімкнути автокопіювання', + 'backup.auto.enableHint': 'Резервні копії створюватимуться автоматично за обраним графіком', + 'backup.auto.interval': 'Інтервал', + 'backup.auto.hour': 'Запуск о', + 'backup.auto.hourHint': 'Місцевий час сервера (формат {format})', + 'backup.auto.dayOfWeek': 'День тижня', + 'backup.auto.dayOfMonth': 'День місяця', + 'backup.auto.dayOfMonthHint': 'Обмежено 1–28 для сумісності з усіма місяцями', + 'backup.auto.scheduleSummary': 'Графік', + 'backup.auto.summaryDaily': 'Щодня о {hour}:00', + 'backup.auto.summaryWeekly': 'Щотижня в {day} о {hour}:00', + 'backup.auto.summaryMonthly': '{day}-го числа кожного місяця о {hour}:00', + 'backup.auto.envLocked': 'Docker', + 'backup.auto.envLockedHint': 'Автокопіювання налаштовано через змінні оточення Docker. Щоб змінити параметри, оновіть docker-compose.yml і перезапустіть контейнер.', + 'backup.auto.copyEnv': 'Скопіювати змінні оточення Docker', + 'backup.auto.envCopied': 'Змінні оточення Docker скопійовано в буфер обміну', + 'backup.auto.keepLabel': 'Видаляти старі копії через', + 'backup.dow.sunday': 'Нд', + 'backup.dow.monday': 'Пн', + 'backup.dow.tuesday': 'Вт', + 'backup.dow.wednesday': 'Ср', + 'backup.dow.thursday': 'Чт', + 'backup.dow.friday': 'Пт', + 'backup.dow.saturday': 'Сб', + 'backup.interval.hourly': 'Кожну годину', + 'backup.interval.daily': 'Щодня', + 'backup.interval.weekly': 'Щотижня', + 'backup.interval.monthly': 'Щомісяця', + 'backup.keep.1day': '1 день', + 'backup.keep.3days': '3 дні', + 'backup.keep.7days': '7 днів', + 'backup.keep.14days': '14 днів', + 'backup.keep.30days': '30 днів', + 'backup.keep.forever': 'Зберігати вічно', + + // Photos + 'photos.title': 'Фотографії', + 'photos.subtitle': '{count} фото для {trip}', + 'photos.dropHere': 'Перетягніть фото сюди...', + 'photos.dropHereActive': 'Перетягніть фото сюди', + 'photos.captionForAll': 'Підпис (для всіх)', + 'photos.captionPlaceholder': 'Необов’язковий підпис...', + 'photos.addCaption': 'Додати підпис...', + 'photos.allDays': 'Усі дні', + 'photos.noPhotos': 'Фото поки немає', + 'photos.uploadHint': 'Завантажте фото з поїздки', + 'photos.clickToSelect': 'або натисніть для вибору', + 'photos.linkPlace': 'Прив’язати місце', + 'photos.noPlace': 'Без місця', + 'photos.uploadN': '{n} фото завантажено', + 'photos.linkDay': 'Прив’язати день', + 'photos.noDay': 'Немає дня', + 'photos.dayLabel': 'День {number}', + 'photos.photoSelected': 'Фото вибрано', + 'photos.photosSelected': 'Фото вибрано', + 'photos.fileTypeHint': 'JPG, PNG, WebP · макс. 10 МБ · до 30 фото', + + // Backup restore modal + 'backup.restoreConfirmTitle': 'Відновити копію?', + 'backup.restoreWarning': 'Усі поточні дані (поїздки, місця, користувачі, завантаження) будуть безповоротно замінені даними з копії. Цю дію неможливо скасувати.', + 'backup.restoreTip': 'Порада: створіть резервну копію поточного стану перед відновленням.', + 'backup.restoreConfirm': 'Так, відновити', + + // PDF + 'pdf.travelPlan': 'План поїздки', + 'pdf.planned': 'Заплановано', + 'pdf.costLabel': 'Вартість EUR', + 'pdf.preview': 'Попередній перегляд PDF', + 'pdf.saveAsPdf': 'Зберегти як PDF', + + // Planner + 'planner.places': 'Місця', + 'planner.bookings': 'Бронювання', + 'planner.packingList': 'Список речей', + 'planner.documents': 'Документи', + 'planner.dayPlan': 'План дня', + 'planner.reservations': 'Бронювання', + 'planner.minTwoPlaces': 'Потрібно мінімум 2 місця з координатами', + 'planner.noGeoPlaces': 'Немає місць з координатами', + 'planner.routeCalculated': 'Маршрут розраховано', + 'planner.routeCalcFailed': 'Не вдалося розрахувати маршрут', + 'planner.routeError': 'Помилка розрахунку маршруту', + 'planner.icsExportFailed': 'Не вдалося експортувати ICS', + 'planner.routeOptimized': 'Маршрут оптимізовано', + 'planner.reservationUpdated': 'Бронювання оновлено', + 'planner.reservationAdded': 'Бронювання додано', + 'planner.confirmDeleteReservation': 'Видалити бронювання?', + 'planner.reservationDeleted': 'Бронювання видалено', + 'planner.days': 'Дні', + 'planner.allPlaces': 'Усі місця', + 'planner.totalPlaces': 'Усього {n} місць', + 'planner.noDaysPlanned': 'Дні ще не заплановано', + 'planner.editTrip': 'Редагувати поїздку →', + 'planner.placeOne': '1 місце', + 'planner.placeN': '{n} місць', + 'planner.addNote': 'Додати нотатку', + 'planner.noEntries': 'На цей день записів немає', + 'planner.addPlace': 'Додати місце/активність', + 'planner.addPlaceShort': '+ Додати місце/активність', + 'planner.resPending': 'Бронювання очікує · ', + 'planner.resConfirmed': 'Бронювання підтверджено · ', + 'planner.notePlaceholder': 'Нотатка…', + 'planner.noteTimePlaceholder': 'Час (необов’язково)', + 'planner.noteExamplePlaceholder': 'наприклад, S3 о 14:30 з вокзалу, пором з причалу 7, обідня перерва…', + 'planner.totalCost': 'Загальна вартість', + 'planner.searchPlaces': 'Пошук місць…', + 'planner.allCategories': 'Усі категорії', + 'planner.noPlacesFound': 'Місця не знайдені', + 'planner.addFirstPlace': 'Додати перше місце', + 'planner.noReservations': 'Немає бронювань', + 'planner.addFirstReservation': 'Додати перше бронювання', + 'planner.new': 'Нове', + 'planner.addToDay': '+ День', + 'planner.calculating': 'Розрахунок…', + 'planner.route': 'Маршрут', + 'planner.optimize': 'Оптимізувати', + 'planner.openGoogleMaps': 'Відкрити в Google Maps', + 'planner.selectDayHint': 'Оберіть день зі списку ліворуч для перегляду плану дня', + 'planner.noPlacesForDay': 'На цей день місць поки немає', + 'planner.addPlacesLink': 'Додати місця →', + 'planner.minTotal': 'мін. всього', + 'planner.noReservation': 'Немає бронювання', + 'planner.removeFromDay': 'Прибрати з дня', + 'planner.addToThisDay': 'Додати до дня', + 'planner.overview': 'Огляд', + 'planner.noDays': 'Днів немає', + 'planner.editTripToAddDays': 'Відредагуйте поїздку, щоб додати дні', + 'planner.dayCount': '{n} днів', + 'planner.clickToUnlock': 'Натисніть, щоб розблокувати', + 'planner.keepPosition': 'Зберегти позицію при оптимізації маршруту', + 'planner.dayDetails': 'Подробиці дня', + 'planner.dayN': 'День {n}', + + // Dashboard Stats + 'stats.countries': 'Країни', + 'stats.cities': 'Міста', + 'stats.trips': 'Поїздки', + 'stats.places': 'Місця', + 'stats.worldProgress': 'Прогрес по світу', + 'stats.visited': 'відвідано', + 'stats.remaining': 'залишилось', + 'stats.visitedCountries': 'Відвідані країни', + + // Day Detail Panel + 'day.precipProb': 'Ймовірність опадів', + 'day.precipitation': 'Опади', + 'day.wind': 'Вітер', + 'day.sunrise': 'Схід', + 'day.sunset': 'Захід', + 'day.hourlyForecast': 'Погодний прогноз по годинах', + 'day.climateHint': 'Історичні середні — реальний прогноз доступний за 16 днів до цієї дати.', + 'day.noWeather': 'Дані про погоду недоступні. Додайте місце з координатами.', + 'day.overview': 'Огляд дня', + 'day.accommodation': 'Проживання', + 'day.addAccommodation': 'Додати проживання', + 'day.hotelDayRange': 'Застосувати до днів', + 'day.noPlacesForHotel': 'Спочатку додайте місця до поїздки', + 'day.allDays': 'Усі', + 'day.checkIn': 'Заїзд', + 'day.checkInUntil': 'До', + 'day.checkOut': 'Виїзд', + 'day.confirmation': 'Підтвердження', + 'day.editAccommodation': 'Редагувати проживання', + 'day.reservations': 'Бронювання', + + // Memories / Immich + 'memories.title': 'Фото', + 'memories.notConnected': 'Immich не підключено', + 'memories.notConnectedHint': 'Підключіть Immich у налаштуваннях, щоб бачити фотографії з поїздок.', + 'memories.notConnectedMultipleHint': 'Підключіть одного з цих фотопровайдерів: {provider_names} у Налаштуваннях, щоб додавати фотографії до цієї подорожі.', + 'memories.noDates': 'Додайте дати поїздки, щоб завантажити фотографії.', + 'memories.noPhotos': 'Фотографій не знайдено', + 'memories.noPhotosHint': 'В Immich немає фотографій за період цієї поїздки.', + 'memories.photosFound': 'фото', + 'memories.fromOthers': 'від інших', + 'memories.sharePhotos': 'Поділитися фото', + 'memories.sharing': 'Спільний доступ', + 'memories.reviewTitle': 'Перевірте свої фото', + 'memories.reviewHint': 'Натисніть на фото, щоб виключити його зі спільного доступу.', + 'memories.shareCount': 'Поділитися ({count} фото)', + 'memories.providerUrl': 'URL сервера', + 'memories.providerApiKey': 'API-ключ', + 'memories.providerUsername': 'Ім’я користувача', + 'memories.providerPassword': 'Пароль', + 'memories.providerOTP': 'Код MFA (якщо увімкнено)', + 'memories.skipSSLVerification': 'Пропустити перевірку SSL-сертифіката', + 'memories.immichAutoUpload': 'Дублювати фото journey в Immich при завантаженні', + 'memories.providerUrlHintSynology': 'Включіть шлях додатку Photos в URL, наприклад https://nas:5001/photo', + 'memories.testConnection': 'Перевірити підключення', + 'memories.testShort': 'Перевірити', + 'memories.testFirst': 'Спершу перевірте підключення', + 'memories.connected': 'Підключено', + 'memories.disconnected': 'Не підключено', + 'memories.connectionSuccess': 'Підключення до Immich встановлено', + 'memories.connectionError': 'Не вдалося підключитися до Immich', + 'memories.saved': 'Налаштування {provider_name} збережено', + 'memories.providerDisconnectedBanner': 'З’єднання з {provider_name} втрачено. Перепідключіться в Налаштуваннях для перегляду фото.', + 'memories.saveError': 'Не вдалося зберегти налаштування {provider_name}', + 'memories.oldest': 'Спочатку старі', + 'memories.newest': 'Спочатку нові', + 'memories.allLocations': 'Усі місця', + 'memories.addPhotos': 'Додати фото', + 'memories.linkAlbum': 'Прив’язати альбом', + 'memories.selectAlbum': 'Вибрати альбом Immich', + 'memories.selectAlbumMultiple': 'Вибрати альбом', + 'memories.noAlbums': 'Альбомів не знайдено', + 'memories.syncAlbum': 'Синхронізувати', + 'memories.unlinkAlbum': 'Відв’язати', + 'memories.photos': 'фото', + 'memories.selectPhotos': 'Вибрати фото з Immich', + 'memories.selectPhotosMultiple': 'Вибрати фотографії', + 'memories.selectHint': 'Натисніть на фото, щоб вибрати їх.', + 'memories.selected': 'вибрано', + 'memories.addSelected': 'Додати {count} фото', + 'memories.alreadyAdded': 'Додано', + 'memories.private': 'Приватне', + 'memories.stopSharing': 'Припинити доступ', + 'memories.tripDates': 'Дати поїздки', + 'memories.allPhotos': 'Усі фото', + 'memories.confirmShareTitle': 'Поділитися з учасниками поїздки?', + 'memories.confirmShareHint': '{count} фото стануть видимі всім учасникам цієї поїздки. Ви зможете зробити окремі фото приватними пізніше.', + 'memories.confirmShareButton': 'Поділитися фото', + + // Collab Addon + 'collab.tabs.chat': 'Чат', + 'collab.tabs.notes': 'Нотатки', + 'collab.tabs.polls': 'Опитування', + 'collab.whatsNext.title': 'Що далі', + 'collab.whatsNext.today': 'Сьогодні', + 'collab.whatsNext.tomorrow': 'Завтра', + 'collab.whatsNext.empty': 'Немає майбутніх активностей', + 'collab.whatsNext.until': 'до', + 'collab.whatsNext.emptyHint': 'Активності з часом відображатимуться тут', + 'collab.chat.send': 'Відправити', + 'collab.chat.placeholder': 'Введіть повідомлення...', + 'collab.chat.empty': 'Розпочніть розмову', + 'collab.chat.emptyHint': 'Повідомлення видимі всім учасникам поїздки', + 'collab.chat.emptyDesc': 'Діліться ідеями, планами та новинами з вашою групою', + 'collab.chat.today': 'Сьогодні', + 'collab.chat.yesterday': 'Вчора', + 'collab.chat.deletedMessage': 'видалив(ла) повідомлення', + 'collab.chat.reply': 'Відповісти', + 'collab.chat.loadMore': 'Завантажити старі повідомлення', + 'collab.chat.justNow': 'щойно', + 'collab.chat.minutesAgo': '{n} хв. тому', + 'collab.chat.hoursAgo': '{n} год. тому', + 'collab.notes.title': 'Нотатки', + 'collab.notes.new': 'Нова нотатка', + 'collab.notes.empty': 'Нотаток поки що немає', + 'collab.notes.emptyHint': 'Почніть записувати ідеї та плани', + 'collab.notes.all': 'Усі', + 'collab.notes.titlePlaceholder': 'Назва нотатки', + 'collab.notes.contentPlaceholder': 'Напишіть щось...', + 'collab.notes.categoryPlaceholder': 'Категорія', + 'collab.notes.newCategory': 'Нова категорія...', + 'collab.notes.category': 'Категорія', + 'collab.notes.noCategory': 'Без категорії', + 'collab.notes.color': 'Колір', + 'collab.notes.save': 'Зберегти', + 'collab.notes.cancel': 'Скасувати', + 'collab.notes.edit': 'Редагувати', + 'collab.notes.delete': 'Видалити', + 'collab.notes.pin': 'Закріпити', + 'collab.notes.unpin': 'Відкріпити', + 'collab.notes.daysAgo': '{n} дн. тому', + 'collab.notes.categorySettings': 'Керування категоріями', + 'collab.notes.create': 'Створити', + 'collab.notes.website': 'Сайт', + 'collab.notes.websitePlaceholder': 'https://...', + 'collab.notes.attachFiles': 'Прикріпити файли', + 'collab.notes.noCategoriesYet': 'Категорій поки що немає', + 'collab.notes.emptyDesc': 'Створіть нотатку, щоб почати', + 'collab.polls.title': 'Опитування', + 'collab.polls.new': 'Нове опитування', + 'collab.polls.empty': 'Опитувань поки що немає', + 'collab.polls.emptyHint': 'Поставте питання групі і голосуйте разом', + 'collab.polls.question': 'Питання', + 'collab.polls.questionPlaceholder': 'Що нам робити?', + 'collab.polls.addOption': '+ Додати варіант', + 'collab.polls.optionPlaceholder': 'Варіант {n}', + 'collab.polls.create': 'Створити опитування', + 'collab.polls.close': 'Закрити', + 'collab.polls.closed': 'Закрите', + 'collab.polls.votes': '{n} голосів', + 'collab.polls.vote': '{n} голос', + 'collab.polls.multipleChoice': 'Багатоваріантний вибір', + 'collab.polls.multiChoice': 'Багатоваріантний вибір', + 'collab.polls.deadline': 'Термін', + 'collab.polls.option': 'Варіант', + 'collab.polls.options': 'Варіанти', + 'collab.polls.delete': 'Видалити', + 'collab.polls.closedSection': 'Закриті', + + // Permissions + 'admin.tabs.permissions': 'Дозволи', + 'perm.title': 'Налаштування дозволів', + 'perm.subtitle': 'Керуйте тим, хто може виконувати дії в додатку', + 'perm.saved': 'Налаштування дозволів збережено', + 'perm.resetDefaults': 'Скинути за замовчуванням', + 'perm.customized': 'змінено', + 'perm.level.admin': 'Тільки адміністратор', + 'perm.level.tripOwner': 'Власник поїздки', + 'perm.level.tripMember': 'Учасники поїздки', + 'perm.level.everybody': 'Усі', + 'perm.cat.trip': 'Керування поїздками', + 'perm.cat.members': 'Керування учасниками', + 'perm.cat.files': 'Файли', + 'perm.cat.content': 'Контент та розклад', + 'perm.cat.extras': 'Бюджет, збори та співпраця', + 'perm.action.trip_create': 'Створювати поїздки', + 'perm.action.trip_edit': 'Редагувати деталі поїздки', + 'perm.action.trip_delete': 'Видаляти поїздки', + 'perm.action.trip_archive': 'Архівувати / розархівувати поїздки', + 'perm.action.trip_cover_upload': 'Завантажувати обкладинку', + 'perm.action.member_manage': 'Додавати / видаляти учасників', + 'perm.action.file_upload': 'Завантажувати файли', + 'perm.action.file_edit': 'Редагувати метадані файлів', + 'perm.action.file_delete': 'Видаляти файли', + 'perm.action.place_edit': 'Додавати / редагувати / видаляти місця', + 'perm.action.day_edit': 'Редагувати дні, нотатки та призначення', + 'perm.action.reservation_edit': 'Керувати бронюваннями', + 'perm.action.budget_edit': 'Керувати бюджетом', + 'perm.action.packing_edit': 'Керувати списками речей', + 'perm.action.collab_edit': 'Співпраця (нотатки, опитування, чат)', + 'perm.action.share_manage': 'Керувати посиланнями для обміну', + 'perm.actionHint.trip_create': 'Хто може створювати нові поїздки', + 'perm.actionHint.trip_edit': 'Хто може змінювати назву, дати, опис і валюту поїздки', + 'perm.actionHint.trip_delete': 'Хто може безповоротно видалити поїздку', + 'perm.actionHint.trip_archive': 'Хто може архівувати або розархівувати поїздку', + 'perm.actionHint.trip_cover_upload': 'Хто може завантажувати або змінювати обкладинку', + 'perm.actionHint.member_manage': 'Хто може запрошувати або видаляти учасників поїздки', + 'perm.actionHint.file_upload': 'Хто може завантажувати файли до поїздки', + 'perm.actionHint.file_edit': 'Хто може редагувати описи та посилання файлів', + 'perm.actionHint.file_delete': 'Хто може переміщувати файли до кошика або безповоротно видаляти', + 'perm.actionHint.place_edit': 'Хто може додавати, редагувати або видаляти місця', + 'perm.actionHint.day_edit': 'Хто може редагувати дні, нотатки до днів та призначення місць', + 'perm.actionHint.reservation_edit': 'Хто може створювати, редагувати або видаляти бронювання', + 'perm.actionHint.budget_edit': 'Хто може створювати, редагувати або видаляти статті бюджету', + 'perm.actionHint.packing_edit': 'Хто може керувати речами для зборів і сумками', + 'perm.actionHint.collab_edit': 'Хто може створювати нотатки, опитування та надсилати повідомлення', + 'perm.actionHint.share_manage': 'Хто може створювати або видаляти публічні посилання для обміну', + // Undo + 'undo.button': 'Відмінити', + 'undo.tooltip': 'Відмінити: {action}', + 'undo.assignPlace': 'Місце додано до дня', + 'undo.removeAssignment': 'Місце вилучено з дня', + 'undo.reorder': 'Місця переставлено', + 'undo.optimize': 'Маршрут оптимізовано', + 'undo.deletePlace': 'Місце видалено', + 'undo.deletePlaces': 'Місця видалено', + 'undo.moveDay': 'Місце переміщено в інший день', + 'undo.lock': 'Блокування місця змінено', + 'undo.importGpx': 'Імпорт GPX', + 'undo.importKeyholeMarkup': 'Імпорт KMZ/KML', + 'undo.importGoogleList': 'Імпорт з Google Maps', + 'undo.importNaverList': 'Імпорт з Naver Maps', + + // Notifications + 'notifications.title': 'Сповіщення', + 'notifications.markAllRead': 'Позначити всі прочитаними', + 'notifications.deleteAll': 'Видалити всі', + 'notifications.showAll': 'Показати всі сповіщення', + 'notifications.empty': 'Немає сповіщень', + 'notifications.emptyDescription': 'Ви в курсі всіх подій!', + 'notifications.all': 'Усі', + 'notifications.unreadOnly': 'Непрочитані', + 'notifications.markRead': 'Позначити як прочитане', + 'notifications.markUnread': 'Позначити як непрочитане', + 'notifications.delete': 'Видалити', + 'notifications.system': 'Система', + 'notifications.synologySessionCleared.title': 'Synology Photos відключено', + 'notifications.synologySessionCleared.text': 'Ваш сервер або акаунт змінено — перейдіть у Налаштування, щоб перевірити з’єднання знову.', + 'memories.error.loadAlbums': 'Не вдалося завантажити альбоми', + 'memories.error.linkAlbum': 'Не вдалося прив\'язати альбом', + 'memories.error.unlinkAlbum': 'Не вдалося від\'вязати альбом', + 'memories.error.syncAlbum': 'Не вдалося синхронізувати альбом', + 'memories.error.loadPhotos': 'Не вдалося завантажити фотографії', + 'memories.error.addPhotos': 'Не вдалося додати фотографії', + 'memories.error.removePhoto': 'Не вдалося видалити фотографію', + 'memories.error.toggleSharing': 'Не вдалося оновити налаштування доступу', + 'undo.addPlace': 'Місце додано', + 'undo.done': 'Відмінено: {action}', + 'notifications.test.title': 'Тестове сповіщення від {actor}', + 'notifications.test.text': 'Це просте тестове сповіщення.', + 'notifications.test.booleanTitle': '{actor} запрошує підтвердження', + 'notifications.test.booleanText': 'Тестове сповіщення з вибором.', + 'notifications.test.accept': 'Підтвердити', + 'notifications.test.decline': 'Відхилити', + 'notifications.test.navigateTitle': 'Подивіться на це', + 'notifications.test.navigateText': 'Тестове сповіщення з переходом.', + 'notifications.test.goThere': 'Перейти', + 'notifications.test.adminTitle': 'Розсилка адміністратора', + 'notifications.test.adminText': '{actor} надіслав тестове сповіщення всім адміністраторам.', + 'notifications.test.tripTitle': '{actor} написав у вашій поїздці', + 'notifications.test.tripText': 'Тестове сповіщення для поїздки "{trip}".', + + // Todo + 'todo.subtab.packing': 'Список речей', + 'todo.subtab.todo': 'Задачі', + 'todo.completed': 'виконано', + 'todo.filter.all': 'Усі', + 'todo.filter.open': 'Відкриття', + 'todo.filter.done': 'Виконані', + 'todo.uncategorized': 'Без категорії', + 'todo.namePlaceholder': 'Назва завдання', + 'todo.descriptionPlaceholder': 'Опис (необов’язково)', + 'todo.unassigned': 'Не призначено', + 'todo.noCategory': 'Без категорії', + 'todo.hasDescription': 'Є опис', + 'todo.addItem': 'Нова задача', + 'todo.sidebar.sortBy': 'Сорзувати за', + 'todo.priority': 'Пріоритет', + 'todo.newCategoryLabel': 'нова', + 'budget.categoriesLabel': 'категорії', + 'todo.newCategory': 'Назва категорії', + 'todo.addCategory': 'Додати категорію', + 'todo.newItem': 'Нова задача', + 'todo.empty': 'Задач поки немає. Додайте задачу, щоб почати!', + 'todo.filter.my': 'Мої задачі', + 'todo.filter.overdue': 'Просрочені', + 'todo.sidebar.tasks': 'Задачі', + 'todo.sidebar.categories': 'Категорії', + 'todo.detail.title': 'Задача', + 'todo.detail.description': 'Опис', + 'todo.detail.category': 'Категорія', + 'todo.detail.dueDate': 'Строк виконання', + 'todo.detail.assignedTo': 'Назначено', + 'todo.detail.delete': 'Видалити', + 'todo.detail.save': 'Зберегти зміни', + 'todo.detail.create': 'Створити задачу', + 'todo.detail.priority': 'Пріоритет', + 'todo.detail.noPriority': 'Немає', + 'todo.sortByPrio': 'Пріоритет', + + // Notification system (added from feat/notification-system) + 'settings.notifyVersionAvailable': 'Доступна нова версія', + 'settings.notificationPreferences.noChannels': 'Канали сповіщень не налаштовані. Попросіть адміністратора налаштувати сповіщення електронною поштою або через webhook.', + 'settings.webhookUrl.label': 'URL вебхука', + 'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...', + 'settings.webhookUrl.hint': 'Введіть URL вашого вебхука Discord, Slack або власного для отримання сповіщень.', + 'settings.webhookUrl.saved': 'URL вебхука збережено', + 'settings.webhookUrl.test': 'Тест', + 'settings.webhookUrl.testSuccess': 'Тестовий вебхук успішно надіслано', + 'settings.webhookUrl.testFailed': 'Помилка тестового вебхука', + 'settings.ntfyUrl.topicLabel': 'Тема Ntfy', + 'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts', + 'settings.ntfyUrl.serverLabel': 'URL сервера Ntfy (необов’язково)', + 'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh', + 'settings.ntfyUrl.hint': 'Введіть тему Ntfy для отримання push-сповіщень. Залиште поле сервера пустим, щоб використовувати налаштування за замовчуванням, задані адміністратором.', + 'settings.ntfyUrl.tokenLabel': 'Токен доступу (необов’язково)', + 'settings.ntfyUrl.tokenHint': 'Потрібно для тем, захищених паролем.', + 'settings.ntfyUrl.saved': 'Налаштування Ntfy збережені', + 'settings.ntfyUrl.test': 'Тест', + 'settings.ntfyUrl.testSuccess': 'Тестове сповіщення Ntfy успішно надіслано', + 'settings.ntfyUrl.testFailed': 'Помилка надсилання тестового сповіщення Ntfy', + 'settings.ntfyUrl.tokenCleared': 'Токен доступу очищено', + 'settings.notificationPreferences.inapp': 'In-App', + 'settings.notificationPreferences.webhook': 'Webhook', + 'settings.notificationPreferences.email': 'Email', + 'settings.notificationPreferences.ntfy': 'Ntfy', + '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': 'Сповіщення', + 'notifications.versionAvailable.title': 'Доступне оновлення', + 'notifications.versionAvailable.text': 'TREK {version} тепер доступний.', + 'notifications.versionAvailable.button': 'Докладніше', + 'notif.test.title': '[Тест] Сповіщення', + 'notif.test.simple.text': 'Це просте тестове сповіщення.', + 'notif.test.boolean.text': 'Ви приймаєте це тестове сповіщення?', + 'notif.test.navigate.text': 'Натисніть нижче, щоб перейти на панель управління.', + + // Notifications + 'notif.trip_invite.title': 'Запрошення до поїздки', + 'notif.trip_invite.text': '{actor} запросив вас до {trip}', + 'notif.booking_change.title': 'Бронювання оновлено', + 'notif.booking_change.text': '{actor} оновив бронювання в {trip}', + 'notif.trip_reminder.title': 'Нагадування про поїздку', + 'notif.trip_reminder.text': 'Ваша поїздка {trip} скоро почнеться!', + 'notif.todo_due.title': 'Завдання до терміну', + 'notif.todo_due.text': '{todo} у {trip} — термін {due}', + 'notif.vacay_invite.title': 'Запрошення Vacay Fusion', + 'notif.vacay_invite.text': '{actor} запрошує вас об’єднати плани відпустки', + 'notif.photos_shared.title': 'Фото опубліковано', + 'notif.photos_shared.text': '{actor} поділився {count} фото у {trip}', + 'notif.collab_message.title': 'Нове повідомлення', + 'notif.collab_message.text': '{actor} надіслав повідомлення в {trip}', + 'notif.packing_tagged.title': 'Завдання для пакування', + 'notif.packing_tagged.text': '{actor} призначив вас у {category} у {trip}', + 'notif.version_available.title': 'Доступна нова версія', + 'notif.version_available.text': 'TREK {version} тепер доступний', + 'notif.action.view_trip': 'Відкрити поїздку', + 'notif.action.view_collab': 'Відкрити повідомлення', + 'notif.action.view_packing': 'Відкрити пакування', + 'notif.action.view_photos': 'Відкрити фото', + 'notif.action.view_vacay': 'Відкрити Vacay', + 'notif.action.view_admin': 'Перейти в адмін', + 'notif.action.view': 'Відкрити', + 'notif.action.accept': 'Прийняти', + 'notif.action.decline': 'Відхилити', + 'notif.generic.title': 'Сповіщення', + 'notif.generic.text': 'У вас нове сповіщення', + 'notif.dev.unknown_event.title': '[DEV] Невідома подія', + 'notif.dev.unknown_event.text': 'Тип події "{event}" не зареєстровано в EVENT_NOTIFICATION_CONFIG', + + // Journey, Dashboard, Nav, DayPlan + 'common.justNow': 'щойно', + 'common.hoursAgo': '{count} год. тому', + 'common.daysAgo': '{count} дн. тому', + 'memories.saveRouteNotConfigured': 'Маршрут збереження не налаштовано для цього провайдера', + 'memories.testRouteNotConfigured': 'Маршрут тестування не налаштовано для цього провайдера', + 'memories.fillRequiredFields': 'Будь ласка, заповніть усі обов’язкові поля', + 'journey.search.placeholder': 'Пошук подорожей…', + 'journey.search.noResults': 'Подорожей за запитом «{query}» не знайдено', + 'journey.title': 'Journey', + 'journey.subtitle': 'Відстежуйте свої подорожі в реальному часі', + 'journey.new': 'Нова подорож', + 'journey.create': 'Створити', + 'journey.titlePlaceholder': 'Куди ви їдете?', + 'journey.empty': 'Поки що немає подорожей', + 'journey.emptyHint': 'Почніть документувати свою наступну поїздку', + 'journey.deleted': 'Подорож видалено', + 'journey.createError': 'Не вдалося створити подорож', + 'journey.deleteError': 'Не вдалося видалити подорож', + 'journey.deleteConfirmTitle': 'Видалити', + 'journey.deleteConfirmMessage': 'Видалити «{title}»? Цю дію не можна скасувати.', + 'journey.deleteConfirmGeneric': 'Ви впевнені, що хочете це видалити?', + 'journey.notFound': 'Подорож не знайдено', + 'journey.photos': 'Фото', + 'journey.timelineEmpty': 'Поки що немає зупинок', + 'journey.timelineEmptyHint': 'Додайте позначку або напишіть запис у щоденник', + 'journey.status.draft': 'Чернетка', + 'journey.status.active': 'Активно', + 'journey.status.completed': 'Завершено', + 'journey.status.upcoming': 'Найближчим часом', + 'journey.status.archived': 'В архіві', + 'journey.checkin.add': 'Відзначитись', + 'journey.checkin.namePlaceholder': 'Назва місця', + 'journey.checkin.notesPlaceholder': 'Нотатки (необов’язково)', + 'journey.checkin.save': 'Зберегти', + 'journey.checkin.error': 'Не вдалося зберегти позначку', + 'journey.entry.add': 'Щоденник', + 'journey.entry.edit': 'Редагувати запис', + 'journey.entry.titlePlaceholder': 'Заголовок (необов’язково)', + 'journey.entry.bodyPlaceholder': 'Що сталося сьогодні?', + 'journey.entry.save': 'Зберегти', + 'journey.entry.error': 'Не вдалося зберегти запис', + 'journey.photo.add': 'Фото', + 'journey.photo.uploadError': 'Завантаження не вдалося', + 'journey.share.share': 'Поділитися', + 'journey.share.public': 'Публічний', + 'journey.share.linkCopied': 'Публічне посилання скопійовано', + 'journey.share.disabled': 'Публічний доступ вимкнено', + 'journey.editor.titlePlaceholder': 'Дайте назву цьому моменту...', + 'journey.editor.bodyPlaceholder': 'Розкажіть історію цього дня...', + 'journey.editor.placePlaceholder': 'Місце розташування (необов’язково)', + 'journey.editor.tagsPlaceholder': 'Теги: прихована перлина, найкраща їжа, варто повернутися...', + 'journey.visibility.private': 'Приватний', + 'journey.visibility.shared': 'Спільний', + 'journey.visibility.public': 'Публічний', + 'journey.emptyState.title': 'Ваша історія починається тут', + 'journey.emptyState.subtitle': 'Позначтесь у місці або напишіть перший запис у щоденник', + 'journey.frontpage.subtitle': 'Перетворюйте поїздки на історії, які ви ніколи не забудете', + 'journey.frontpage.createJourney': 'Створити подорож', + 'journey.frontpage.activeJourney': 'Активна подорож', + 'journey.frontpage.allJourneys': 'Усі подорожі', + 'journey.frontpage.journeys': 'подорожей', + 'journey.frontpage.createNew': 'Створити нову подорож', + 'journey.frontpage.createNewSub': 'Оберіть поїздки, пишіть історії, діліться пригодами', + 'journey.frontpage.live': 'В ефірі', + 'journey.frontpage.synced': 'Синхронізовано', + 'journey.frontpage.continueWriting': 'Продовжити писати', + 'journey.frontpage.updated': 'Оновлено {time}', + 'journey.frontpage.suggestionLabel': 'Поїздка щойно завершилась', + 'journey.frontpage.suggestionText': 'Перетворіть {title} на подорож', + 'journey.frontpage.dismiss': 'Приховати', + 'journey.frontpage.journeyName': 'Назва подорожі', + 'journey.frontpage.namePlaceholder': 'наприклад, Південно-Східна Азія 2026', + 'journey.frontpage.selectTrips': 'Оберіть поїздки', + 'journey.frontpage.tripsSelected': 'поїздок вибрано', + 'journey.frontpage.trips': 'поїздок', + 'journey.frontpage.placesImported': 'місць буде імпортовано', + 'journey.frontpage.places': 'місць', + 'journey.detail.backToJourney': 'Назад до подорожі', + 'journey.detail.syncedWithTrips': 'Синхронізовано з поїздками', + 'journey.detail.addEntry': 'Додати запис', + 'journey.detail.newEntry': 'Новий запис', + 'journey.detail.editEntry': 'Редагувати запис', + 'journey.detail.noEntries': 'Поки що немає записів', + 'journey.detail.noEntriesHint': 'Додайте подорож, щоб почати зі шаблонних записів', + 'journey.detail.noPhotos': 'Поки що немає фото', + 'journey.detail.noPhotosHint': 'Завантажте фото до записів або перегляньте бібліотеку Immich/Synology', + 'journey.detail.journeyStats': 'Статистика подорожі', + 'journey.detail.syncedTrips': 'Синхронізовані поїздки', + 'journey.detail.noTripsLinked': 'Поки що немає прив’язаних поїздок', + 'journey.detail.contributors': 'Учасники', + 'journey.detail.journeyTab': 'Journey', + 'journey.detail.readMore': 'Читати далі', + 'journey.detail.prosCons': 'Плюси й мінуси', + 'journey.detail.photos': 'фото', + 'journey.detail.day': 'День {number}', + 'journey.detail.places': 'місць', + 'journey.stats.days': 'Днів', + 'journey.stats.cities': 'Міст', + 'journey.stats.entries': 'Записів', + 'journey.stats.photos': 'Фото', + 'journey.stats.places': 'Місць', + 'journey.skeletons.show': 'Показати пропозиції', + 'journey.skeletons.hide': 'Приховати пропозиції', + 'journey.verdict.lovedIt': 'Сподобалось', + 'journey.verdict.couldBeBetter': 'Могло бути краще', + 'journey.synced.places': 'місць', + 'journey.synced.synced': 'синхронізовано', + 'journey.editor.discardChangesConfirm': 'У вас є незбережені зміни. Відмінити?', + 'journey.editor.uploadPhotos': 'Завантажити фото', + 'journey.editor.uploading': 'Завантаження...', + 'journey.editor.fromGallery': 'Зі галереї', + 'journey.editor.allPhotosAdded': 'Усі фото вже додано', + 'journey.editor.writeStory': 'Напишіть свою історію...', + 'journey.editor.prosCons': 'Плюси й мінуси', + 'journey.editor.pros': 'Плюси', + 'journey.editor.cons': 'Мінуси', + 'journey.editor.proPlaceholder': 'Щось чудове...', + 'journey.editor.conPlaceholder': 'Не дуже добре...', + 'journey.editor.addAnother': 'Додати ще', + 'journey.editor.date': 'Дата', + 'journey.editor.location': 'Місце розташування', + 'journey.editor.searchLocation': 'Пошук місця розташування...', + 'journey.editor.mood': 'Настрій', + 'journey.editor.weather': 'Погода', + 'journey.editor.photoFirst': '1-е', + 'journey.editor.makeFirst': 'Зробити першим', + 'journey.editor.searching': 'Пошук...', + 'journey.mood.amazing': 'Неймовірно', + 'journey.mood.good': 'Добре', + 'journey.mood.neutral': 'Нейтрально', + 'journey.mood.rough': 'Важко', + 'journey.weather.sunny': 'Сонячно', + 'journey.weather.partly': 'Перемінна хмарність', + 'journey.weather.cloudy': 'Хмарно', + 'journey.weather.rainy': 'Дощ', + 'journey.weather.stormy': 'Гроза', + 'journey.weather.cold': 'Сніжно', + 'journey.trips.linkTrip': 'Прив’язати поїздку', + 'journey.trips.searchTrip': 'Пошук поїздки', + 'journey.trips.searchPlaceholder': 'Назва поїздки або напрям...', + 'journey.trips.noTripsAvailable': 'Немає доступних поїздок', + 'journey.trips.link': 'Прив’язати', + 'journey.trips.tripLinked': 'Поїздка прив’язана', + 'journey.trips.linkFailed': 'Не вдалося прив’язати поїздку', + 'journey.trips.addTrip': 'Додати поїздку', + 'journey.trips.unlinkTrip': 'Відв’язати поїздку', + 'journey.trips.unlinkMessage': 'Відв’язати «{title}»? Усі синхронізовані записи та фото з цієї поїздки будуть безповоротно видалені. Цю дію не можна скасувати.', + 'journey.trips.unlink': 'Відв’язати', + 'journey.trips.tripUnlinked': 'Поїздка відв’язана', + 'journey.trips.unlinkFailed': 'Не вдалося відв’язати поїздку', + 'journey.trips.noTripsLinkedSettings': 'Немає прив’язаних поїздок', + 'journey.contributors.invite': 'Запросити учасника', + 'journey.contributors.searchUser': 'Пошук користувача', + 'journey.contributors.searchPlaceholder': 'Ім’я користувача або email...', + 'journey.contributors.noUsers': 'Користувачів не знайдено', + 'journey.contributors.role': 'Роль', + 'journey.contributors.added': 'Учасника додано', + 'journey.contributors.addFailed': 'Не вдалося додати учасника', + 'journey.contributors.remove': 'Вилучити учасника', + 'journey.contributors.removeConfirm': 'Вилучити {username} з цієї подорожі?', + 'journey.contributors.removeFailed': 'Не вдалося вилучити учасника', + 'journey.contributors.removed': 'Учасника вилучено', + 'journey.share.publicShare': 'Публічний доступ', + 'journey.share.createLink': 'Створити посилання для спільного доступу', + 'journey.share.linkCreated': 'Посилання створено', + 'journey.share.createFailed': 'Не вдалося створити посилання', + 'journey.share.copy': 'Копіювати', + 'journey.share.copied': 'Скопійовано!', + 'journey.share.timeline': 'Хронологія', + 'journey.share.gallery': 'Галерея', + 'journey.share.map': 'Карта', + 'journey.share.removeLink': 'Видалити посилання', + 'journey.share.linkDeleted': 'Посилання видалено', + 'journey.share.deleteFailed': 'Не вдалося видалити', + 'journey.share.updateFailed': 'Не вдалося оновити', + + // Journey — Invite + 'journey.invite.role': 'Роль', + 'journey.invite.viewer': 'Спостерігач', + 'journey.invite.editor': 'Редактор', + 'journey.invite.invite': 'Запросити', + 'journey.invite.inviting': 'Запрошуємо...', + 'journey.settings.title': 'Налаштування подорожі', + 'journey.settings.coverImage': 'Обкладинка', + 'journey.settings.changeCover': 'Змінити обкладинку', + 'journey.settings.addCover': 'Додати обкладинку', + 'journey.settings.name': 'Назва', + 'journey.settings.subtitle': 'Підзаголовок', + 'journey.settings.subtitlePlaceholder': 'наприклад Таїланд, В’єтнам і Камбоджа', + 'journey.settings.endJourney': 'Архівувати подорож', + 'journey.settings.reopenJourney': 'Відновити подорож', + 'journey.settings.archived': 'Подорож архівовано', + 'journey.settings.reopened': 'Подорож відновлено', + 'journey.settings.endDescription': 'Приховує значок «В ефірі». Ви можете відновити у будь-який час.', + 'journey.settings.delete': 'Видалити', + 'journey.settings.deleteJourney': 'Видалити подорож', + 'journey.settings.deleteMessage': 'Видалити «{title}»? Усі записи та фото будуть втрачені.', + 'journey.settings.saved': 'Налаштування збережено', + 'journey.settings.saveFailed': 'Не вдалося зберегти', + 'journey.settings.coverUpdated': 'Обкладинка оновлено', + 'journey.settings.coverFailed': 'Завантаження не вдалося', + 'journey.settings.failedToDelete': 'Не вдалося видалити', + 'journey.entries.deleteTitle': 'Видалити запис', + 'journey.photosUploaded': '{count} фото завантажено', + 'journey.photosAdded': '{count} фото додано', + 'journey.public.notFound': 'Не знайдено', + 'journey.public.notFoundMessage': 'Ця подорож не існує або посилання застаріло.', + 'journey.public.readOnly': 'Тільки для читання · Публічна подорож', + 'journey.public.tagline': 'Інструмент планування та дослідження подорожей', + 'journey.public.sharedVia': 'Опубліковано через', + 'journey.public.madeWith': 'Зроблено з допомогою', + 'journey.pdf.journeyBook': 'Книга подорожі', + 'journey.pdf.madeWith': 'Зроблено з допомогою TREK', + 'journey.pdf.day': 'День', + 'journey.pdf.theEnd': 'Кінець', + 'journey.pdf.saveAsPdf': 'Зберегти як PDF', + 'journey.pdf.pages': 'сторінок', + 'journey.picker.tripPeriod': 'Період подорожі', + 'journey.picker.dateRange': 'Діапазон дат', + 'journey.picker.allPhotos': 'Усі фото', + 'journey.picker.albums': 'Альбоми', + 'journey.picker.selected': 'вибрано', + 'journey.picker.addTo': 'Додати до', + 'journey.picker.newGallery': 'Нова галерея', + 'journey.picker.selectAll': 'Вибрати все', + 'journey.picker.deselectAll': 'Скасувати вибір', + 'journey.picker.noAlbums': 'Альбомів не знайдено', + 'journey.picker.selectDate': 'Оберіть дату', + 'journey.picker.search': 'Пошук', + 'dashboard.greeting.morning': 'Доброго ранку,', + 'dashboard.greeting.afternoon': 'Доброго дня,', + 'dashboard.greeting.evening': 'Доброго вечора,', + 'dashboard.mobile.liveNow': 'Зараз у дорозі', + 'dashboard.mobile.tripProgress': 'Прогрес поїздки', + 'dashboard.mobile.daysLeft': 'залишилось {count} дн.', + 'dashboard.mobile.places': 'Місця', + 'dashboard.mobile.buddies': 'Учасники', + 'dashboard.mobile.newTrip': 'Нова поїздка', + 'dashboard.mobile.currency': 'Валюта', + 'dashboard.mobile.timezone': 'Часовий пояс', + 'dashboard.mobile.upcomingTrips': 'Найближчі поїздки', + 'dashboard.mobile.yourTrips': 'Ваші поїздки', + 'dashboard.mobile.trips': 'поїздок', + 'dashboard.mobile.starts': 'Початок', + 'dashboard.mobile.duration': 'Тривалість', + 'dashboard.mobile.day': 'день', + 'dashboard.mobile.days': 'днів', + 'dashboard.mobile.ongoing': 'Триває', + 'dashboard.mobile.startsToday': 'Починається сьогодні', + 'dashboard.mobile.tomorrow': 'Завтра', + 'dashboard.mobile.inDays': 'Через {count} дн.', + 'dashboard.mobile.inMonths': 'Через {count} міс.', + 'dashboard.mobile.completed': 'Завершено', + 'dashboard.mobile.currencyConverter': 'Конвертер валют', + 'nav.profile': 'Профіль', + 'nav.bottomSettings': 'Налаштування', + 'nav.bottomAdmin': 'Адміністрування', + 'nav.bottomLogout': 'Вийти', + 'nav.bottomAdminBadge': 'Адмін', + 'dayplan.mobile.addPlace': 'Додати місце', + 'dayplan.mobile.searchPlaces': 'Пошук місць...', + 'dayplan.mobile.allAssigned': 'Усі місця розподілені', + 'dayplan.mobile.noMatch': 'Немає збігів', + 'dayplan.mobile.createNew': 'Створити нове місце', + 'admin.addons.catalog.journey.name': 'Journey', + 'admin.addons.catalog.journey.description': 'Відстеження поїздок і щоденник подорожей з позначками, фото та щоденними історіями', + + // OAuth scope groups + 'oauth.scope.group.trips': 'Поїздки', + 'oauth.scope.group.places': 'Місця', + 'oauth.scope.group.atlas': 'Atlas', + 'oauth.scope.group.packing': 'Речі', + 'oauth.scope.group.todos': 'Задачі', + 'oauth.scope.group.budget': 'Бюджет', + 'oauth.scope.group.reservations': 'Бронювання', + 'oauth.scope.group.collab': 'Співпраця', + 'oauth.scope.group.notifications': 'Сповіщення', + 'oauth.scope.group.vacay': 'Відпустка', + 'oauth.scope.group.geo': 'Geo', + 'oauth.scope.group.weather': 'Погода', + 'oauth.scope.group.journey': 'Подорожі', + + // OAuth scope labels & descriptions + 'oauth.scope.trips:read.label': 'Перегляд поїздок і маршрутів', + 'oauth.scope.trips:read.description': 'Читання поїздок, днів, нотаток і учасників', + 'oauth.scope.trips:write.label': 'Редагування поїздок і маршрутів', + 'oauth.scope.trips:write.description': 'Створення та оновлення поїздок, днів, нотаток і керування учасниками', + 'oauth.scope.trips:delete.label': 'Видалення поїздок', + 'oauth.scope.trips:delete.description': 'Безповоротне видалення поїздок — ця дія незворотна', + 'oauth.scope.trips:share.label': 'Керування посиланнями спільного доступу', + 'oauth.scope.trips:share.description': 'Створення, оновлення та відкликання публічних посилань на поїздки', + 'oauth.scope.places:read.label': 'Перегляд місць і даних карти', + 'oauth.scope.places:read.description': 'Читання місць, призначень за днями, тегів і категорій', + 'oauth.scope.places:write.label': 'Керування місцями', + 'oauth.scope.places:write.description': 'Створення, оновлення та видалення місць, призначень і тегів', + 'oauth.scope.atlas:read.label': 'Перегляд Atlas', + 'oauth.scope.atlas:read.description': 'Читання відвіданих країн, регіонів і списку бажань', + 'oauth.scope.atlas:write.label': 'Керування Atlas', + 'oauth.scope.atlas:write.description': 'Позначення відвіданих країн і регіонів, керування списком бажань', + 'oauth.scope.packing:read.label': 'Перегляд списків речей', + 'oauth.scope.packing:read.description': 'Читання речей, сумок і призначень категорій', + 'oauth.scope.packing:write.label': 'Керування списками речей', + 'oauth.scope.packing:write.description': 'Додавання, оновлення, видалення, позначення і переставлення речей та сумок', + 'oauth.scope.todos:read.label': 'Перегляд списків задач', + 'oauth.scope.todos:read.description': 'Читання задач поїздки і призначень категорій', + 'oauth.scope.todos:write.label': 'Керування списками задач', + 'oauth.scope.todos:write.description': 'Створення, оновлення, позначення, видалення і переставлення задач', + 'oauth.scope.budget:read.label': 'Перегляд бюджету', + 'oauth.scope.budget:read.description': 'Читання статей бюджету і розбивки витрат', + 'oauth.scope.budget:write.label': 'Керування бюджетом', + 'oauth.scope.budget:write.description': 'Створення, оновлення і видалення статей бюджету', + 'oauth.scope.reservations:read.label': 'Перегляд бронювань', + 'oauth.scope.reservations:read.description': 'Читання бронювань і відомостей про проживання', + 'oauth.scope.reservations:write.label': 'Керування бронюваннями', + 'oauth.scope.reservations:write.description': 'Створення, оновлення, видалення і переставлення бронювань', + 'oauth.scope.collab:read.label': 'Перегляд співпраці', + 'oauth.scope.collab:read.description': 'Читання спільних нотаток, опитувань і повідомлень', + 'oauth.scope.collab:write.label': 'Керування співпрацею', + 'oauth.scope.collab:write.description': 'Створення, оновлення і видалення нотаток, опитувань і повідомлень', + 'oauth.scope.notifications:read.label': 'Перегляд сповіщень', + 'oauth.scope.notifications:read.description': 'Читання сповіщень у додатку та кількості непрочитаних', + 'oauth.scope.notifications:write.label': 'Керування сповіщеннями', + 'oauth.scope.notifications:write.description': 'Позначення сповіщень як прочитаних і відповіді на них', + 'oauth.scope.vacay:read.label': 'Перегляд планів відпустки', + 'oauth.scope.vacay:read.description': 'Читання даних планування відпустки, записів і статистики', + 'oauth.scope.vacay:write.label': 'Керування планами відпустки', + 'oauth.scope.vacay:write.description': 'Створення і керування записами відпустки, святами і командними планами', + 'oauth.scope.geo:read.label': 'Карти і геокодування', + 'oauth.scope.geo:read.description': 'Пошук місць, розв’язання URL карт і зворотне геокодування координат', + 'oauth.scope.weather:read.label': 'Прогнози погоди', + 'oauth.scope.weather:read.description': 'Отримання прогнозів погоди для місць і дат поїздки', + 'oauth.scope.journey:read.label': 'Перегляд подорожей', + 'oauth.scope.journey:read.description': 'Читання подорожей, записів і списку учасників', + 'oauth.scope.journey:write.label': 'Керування подорожами', + 'oauth.scope.journey:write.description': 'Створення, оновлення і видалення подорожей та їх записів', + 'oauth.scope.journey:share.label': 'Керування посиланнями на подорожі', + 'oauth.scope.journey:share.description': 'Створення, оновлення і відкликання публічних посилань на подорожі', + + // System notices + 'system_notice.welcome_v1.title': 'Ласкаво просимо в TREK', + 'system_notice.welcome_v1.body': 'Ваш універсальний планувальник подорожей. Створюйте маршрути, діліться поїздками з друзями та залишайтесь організованими — онлайн та офлайн.', + 'system_notice.welcome_v1.cta_label': 'Спланувати поїздку', + 'system_notice.welcome_v1.hero_alt': 'Живописне місце призначення з інтерфейсом TREK', + 'system_notice.welcome_v1.highlight_plan': 'Детальні плани по днях для будь-яких поїздок', + 'system_notice.welcome_v1.highlight_share': 'Спільне планування', + 'system_notice.welcome_v1.highlight_offline': 'Працює офлайн на мобільному', + 'system_notice.dev_test_modal.title': '[Dev] Test notice', + 'system_notice.dev_test_modal.body': 'This is a dev-only test notice.', + 'system_notice.pager.prev': 'Попереднє повідомлення', + 'system_notice.pager.next': 'Наступне повідомлення', + 'system_notice.pager.counter': '{current} / {total}', + 'system_notice.pager.goto': 'Перейти до повідомлення {n}', + 'system_notice.pager.position': 'Повідомлення {current} із {total}', + // System notices — 3.0.0 upgrade + 'system_notice.v3_photos.title': 'Фото переміщено у версії 3.0', + 'system_notice.v3_photos.body': 'Вкладку **Фото** в Планувальнику подорожей видалено. Ваші фото в безпеці — TREK ніколи не змінював вашу бібліотеку Immich або Synology.\n\nФото тепер доступні у доповненні **Journey**. Journey необов’язковий — якщо він ще недоступний, попросіть адміністратора включити його в розділі Адмін → Додатки.', + 'system_notice.v3_journey.title': 'Знайомтесь із Journey', + 'system_notice.v3_journey.body': 'Документуйте подорожі як історії з хронологіями, фотогалереями та інтерактивними картами.', + 'system_notice.v3_journey.cta_label': 'Відкрити Journey', + 'system_notice.v3_journey.highlight_timeline': 'Щоденна хронологія та галерея', + 'system_notice.v3_journey.highlight_photos': 'Імпорт з Immich або Synology', + 'system_notice.v3_journey.highlight_share': 'Спільний доступ — без входу', + 'system_notice.v3_journey.highlight_export': 'Експорт у PDF-фотокнигу', + 'system_notice.v3_features.title': 'Ще більше нового у версії 3.0', + 'system_notice.v3_features.body': 'Декілька інших важливих нововведень у цьому релізі.', + 'system_notice.v3_features.highlight_dashboard': 'Перероблена панель у mobile-first стилі', + 'system_notice.v3_features.highlight_offline': 'Повний офлайн-режим як PWA', + 'system_notice.v3_features.highlight_search': 'Автодоповнення пошуку місць у реальному часі', + 'system_notice.v3_features.highlight_import': 'Імпорт місць з KMZ/KML-файлів', + + // System notices — MCP OAuth 2.1 upgrade + 'system_notice.v3_mcp.title': 'MCP: оновлення OAuth 2.1', + 'system_notice.v3_mcp.body': 'Інтеграція MCP була повністю перероблена. OAuth 2.1 тепер є рекомендованим методом автентифікації. Статичні токени (trek_…) застаріли і будуть видалені в майбутній версії.', + 'system_notice.v3_mcp.highlight_oauth': 'OAuth 2.1 рекомендовано (mcp-remote)', + 'system_notice.v3_mcp.highlight_scopes': '24 детальні області дозволів', + 'system_notice.v3_mcp.highlight_deprecated': 'Статичні токени trek_ застаріли', + 'system_notice.v3_mcp.highlight_tools': 'Розширений набір інструментів', + + // System notices — personal thank you + 'system_notice.v3_thankyou.title': 'Особливе слово від мене', + 'system_notice.v3_thankyou.body': 'Перш ніж продовжити — хочу зупинитися на мить.\n\nTREK починався як сторонній проєкт, який я створив для власних поїздок. Я ніколи не думав, що він виросте в щось, чому 4 000 з вас довіряють планування своїх пригод. Кожна зірочка, кожен issue, кожен запит на фічу — я читаю їх усі, і саме вони підтримують мене у пізні ночі між основною роботою та університетом.\n\nХочу, щоб ви знали: TREK завжди буде open source, завжди self-hosted, завжди вашим. Жодного стеження, жодних підписок, жодних підводних каменів. Просто інструмент, створений людиною, яка любить подорожувати так само, як і ви.\n\nОсоблива подяка [jubnl](https://github.com/jubnl) — ти став неймовірним соратником. Багато з того, що робить версію 3.0 чудовою, несе твій відбиток. Дякую, що повірив у цей проєкт, коли він ще був сирим.\n\nІ кожному з вас, хто повідомив про помилку, переклав рядок, поділився TREK з другом або просто використовував його для планування поїздки — **дякую**. Ви — причина, чому все це існує.\n\nЗа багато нових пригод разом.\n\n— Maurice\n\n---\n\n[Приєднуйтесь до спільноти в Discord](https://discord.gg/7Q6M6jDwzf)\n\nЯкщо TREK робить ваші подорожі кращими, [невелика кава](https://ko-fi.com/mauriceboe) завжди допомагає тримати світло ввімкненим.', + 'transport.addTransport': 'Додати транспорт', + 'transport.modalTitle.create': 'Додати транспорт', + 'transport.modalTitle.edit': 'Змінити транспорт', + 'transport.title': 'Транспорт', + 'transport.addManual': 'Ручний транспорт', + + // Added to match EN keys + 'journey.editor.uploadingProgress': 'Завантаження {done}/{total}…', + 'journey.editor.uploadFailed': 'Не вдалося завантажити фото', + 'journey.editor.uploadPartialFailed': '{failed} з {total} фото не вдалося завантажити — збережіть ще раз, щоб повторити', + 'journey.photosUploadFailed': 'Деякі фото не вдалося завантажити', + 'settings.oauth.modal.machineClient': 'Машинний клієнт (без входу через браузер)', + 'settings.oauth.modal.machineClientHint': 'Використовуйте надання client_credentials — URI перенаправлення не потрібні. Токен видається безпосередньо через client_id + client_secret і діє від вашого імені в межах вибраних областей.', + 'settings.oauth.modal.machineClientUsage': 'Отримати токен: POST /oauth/token з grant_type=client_credentials, client_id і client_secret. Без браузера, без токена оновлення.', + 'settings.oauth.badge.machine': 'машина', + 'files.assignTransport': 'Транспорт', + 'files.sourceTransport': 'Транспорт', + 'system_notice.v3014_whitespace_collision.title': 'Потрібна дія: конфлікт облікового запису користувача', + 'system_notice.v3014_whitespace_collision.body': 'Оновлення 3.0.14 виявило один або кілька конфліктів імен користувачів або електронних адрес, спричинених початковими або кінцевими пробілами в збережених облікових записах. Уражені облікові записи було автоматично перейменовано. Перевірте журнали сервера на рядки, що починаються з **[migration] WHITESPACE COLLISION**, щоб визначити, які облікові записи потребують перевірки.', +} + +export default uk + diff --git a/client/tests/unit/i18n/index.test.ts b/client/tests/unit/i18n/index.test.ts index 9be7d94d..9260b732 100644 --- a/client/tests/unit/i18n/index.test.ts +++ b/client/tests/unit/i18n/index.test.ts @@ -91,10 +91,12 @@ describe('isRtlLanguage', () => { describe('SUPPORTED_LANGUAGES', () => { it('FE-COMP-I18N-009: contains expected entries with value/label shape', () => { expect(Array.isArray(SUPPORTED_LANGUAGES)).toBe(true) - expect(SUPPORTED_LANGUAGES).toHaveLength(17) + expect(SUPPORTED_LANGUAGES).toHaveLength(19) expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'en', label: 'English' })) expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'tr', label: 'Türkçe' })) expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'ja', label: '日本語' })) + expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'ko', label: '한국어' })) + expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'uk', label: 'Українська' })) expect(SUPPORTED_LANGUAGES).toContainEqual(expect.objectContaining({ value: 'ar', label: 'العربية' })) }) })