fix(costs): rework the cost panel UX wise and apply prettier on the shared package

This commit is contained in:
jubnl
2026-06-18 13:59:10 +02:00
parent ad6e1ddcc8
commit d5850041a7
584 changed files with 6915 additions and 10724 deletions
+52 -98
View File
@@ -2,8 +2,7 @@ import type { TranslationStrings } from '../types';
const admin: TranslationStrings = {
'admin.notifications.title': 'Уведомления',
'admin.notifications.hint':
'Выберите канал уведомлений. Одновременно может быть активен только один.',
'admin.notifications.hint': 'Выберите канал уведомлений. Одновременно может быть активен только один.',
'admin.notifications.none': 'Отключено',
'admin.notifications.email': 'Эл. почта (SMTP)',
'admin.notifications.webhook': 'Webhook',
@@ -13,11 +12,9 @@ const admin: TranslationStrings = {
'admin.notifications.testWebhookSuccess': 'Тестовый вебхук успешно отправлен',
'admin.notifications.testWebhookFailed': 'Ошибка отправки тестового вебхука',
'admin.smtp.title': 'Почта и уведомления',
'admin.smtp.hint':
'Конфигурация SMTP для отправки уведомлений по электронной почте.',
'admin.smtp.hint': 'Конфигурация SMTP для отправки уведомлений по электронной почте.',
'admin.smtp.testButton': 'Отправить тестовое письмо',
'admin.webhook.hint':
'Отправлять уведомления через внешний webhook (Discord, Slack и т.д.).',
'admin.webhook.hint': 'Отправлять уведомления через внешний webhook (Discord, Slack и т.д.).',
'admin.smtp.testSuccess': 'Тестовое письмо успешно отправлено',
'admin.smtp.testFailed': 'Ошибка отправки тестового письма',
'admin.title': 'Администрирование',
@@ -41,8 +38,7 @@ const admin: TranslationStrings = {
'admin.editUser': 'Редактировать пользователя',
'admin.newPassword': 'Новый пароль',
'admin.newPasswordHint': 'Оставьте пустым, чтобы сохранить текущий пароль',
'admin.deleteUser':
'Удалить пользователя «{name}»? Все поездки будут безвозвратно удалены.',
'admin.deleteUser': 'Удалить пользователя «{name}»? Все поездки будут безвозвратно удалены.',
'admin.deleteUserTitle': 'Удалить пользователя',
'admin.newPasswordPlaceholder': 'Введите новый пароль…',
'admin.toast.loadError': 'Не удалось загрузить данные администрирования',
@@ -53,8 +49,7 @@ const admin: TranslationStrings = {
'admin.toast.cannotDeleteSelf': 'Нельзя удалить собственный аккаунт',
'admin.toast.userCreated': 'Пользователь создан',
'admin.toast.createError': 'Ошибка создания пользователя',
'admin.toast.fieldsRequired':
'Имя пользователя, эл. почта и пароль обязательны',
'admin.toast.fieldsRequired': 'Имя пользователя, эл. почта и пароль обязательны',
'admin.createUser': 'Создать пользователя',
'admin.invite.title': 'Ссылки-приглашения',
'admin.invite.subtitle': 'Создание одноразовых ссылок для регистрации',
@@ -76,19 +71,16 @@ const admin: TranslationStrings = {
'admin.invite.deleteError': 'Ошибка при удалении ссылки',
'admin.tabs.settings': 'Настройки',
'admin.allowRegistration': 'Разрешить регистрацию',
'admin.allowRegistrationHint':
'Новые пользователи могут регистрироваться самостоятельно',
'admin.allowRegistrationHint': 'Новые пользователи могут регистрироваться самостоятельно',
'admin.authMethods': 'Authentication Methods',
'admin.passwordLogin': 'Password Login',
'admin.passwordLoginHint': 'Allow users to sign in with email and password',
'admin.passwordRegistration': 'Password Registration',
'admin.passwordRegistrationHint':
'Allow new users to register with email and password',
'admin.passwordRegistrationHint': 'Allow new users to register with email and password',
'admin.oidcLogin': 'SSO Login',
'admin.oidcLoginHint': 'Allow users to sign in with SSO',
'admin.oidcRegistration': 'SSO Auto-Provisioning',
'admin.oidcRegistrationHint':
'Automatically create accounts for new SSO users',
'admin.oidcRegistrationHint': 'Automatically create accounts for new SSO users',
'admin.envOverrideHint':
'Password login settings are controlled by the OIDC_ONLY environment variable and cannot be changed here.',
'admin.lockoutWarning': 'At least one login method must remain enabled',
@@ -96,37 +88,30 @@ const admin: TranslationStrings = {
'admin.requireMfaHint':
'Пользователи без 2FA должны завершить настройку в разделе «Настройки» перед использованием приложения.',
'admin.apiKeys': 'API-ключи',
'admin.apiKeysHint':
'Необязательно. Включает расширенные данные о местах, такие как фото и погода.',
'admin.apiKeysHint': 'Необязательно. Включает расширенные данные о местах, такие как фото и погода.',
'admin.mapsKey': 'API-ключ Google Maps',
'admin.mapsKeyHint':
'Необходим для поиска мест. Получите на console.cloud.google.com',
'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.weatherKeyHint': 'Для данных о погоде. Бесплатно на openweathermap.org',
'admin.validateKey': 'Проверить',
'admin.keyValid': 'Подключено',
'admin.keyInvalid': 'Недействителен',
'admin.keySaved': 'API-ключи сохранены',
'admin.oidcTitle': 'Единый вход (OIDC)',
'admin.oidcSubtitle':
'Разрешить вход через внешних провайдеров, таких как Google, Apple, Authentik или Keycloak.',
'admin.oidcSubtitle': 'Разрешить вход через внешних провайдеров, таких как Google, Apple, Authentik или Keycloak.',
'admin.oidcDisplayName': 'Отображаемое имя',
'admin.oidcIssuer': 'URL издателя',
'admin.oidcIssuerHint':
'URL издателя OpenID Connect провайдера. Напр. https://accounts.google.com',
'admin.oidcIssuerHint': 'URL издателя OpenID Connect провайдера. Напр. https://accounts.google.com',
'admin.oidcSaved': 'Конфигурация OIDC сохранена',
'admin.oidcOnlyMode': 'Отключить вход по паролю',
'admin.oidcOnlyModeHint':
'При включении разрешён только вход через SSO. Вход и регистрация по паролю будут заблокированы.',
'admin.fileTypes': 'Разрешённые типы файлов',
'admin.fileTypesHint':
'Настройте, какие типы файлов могут загружать пользователи.',
'admin.fileTypesFormat':
'Расширения через запятую (напр. jpg,png,pdf,doc). Используйте * для разрешения всех типов.',
'admin.fileTypesHint': 'Настройте, какие типы файлов могут загружать пользователи.',
'admin.fileTypesFormat': 'Расширения через запятую (напр. jpg,png,pdf,doc). Используйте * для разрешения всех типов.',
'admin.fileTypesSaved': 'Настройки типов файлов сохранены',
'admin.placesPhotos.title': 'Фотографии мест',
'admin.placesPhotos.subtitle':
@@ -157,11 +142,9 @@ const admin: TranslationStrings = {
'admin.defaultSettings.resetToBuiltIn': 'сбросить',
'admin.tabs.templates': 'Шаблоны упаковки',
'admin.packingTemplates.title': 'Шаблоны упаковки',
'admin.packingTemplates.subtitle':
'Создавайте многоразовые списки вещей для поездок',
'admin.packingTemplates.subtitle': 'Создавайте многоразовые списки вещей для поездок',
'admin.packingTemplates.create': 'Новый шаблон',
'admin.packingTemplates.namePlaceholder':
'Название шаблона (напр. Пляжный отдых)',
'admin.packingTemplates.namePlaceholder': 'Название шаблона (напр. Пляжный отдых)',
'admin.packingTemplates.empty': 'Шаблоны ещё не созданы',
'admin.packingTemplates.items': 'вещей',
'admin.packingTemplates.categories': 'категорий',
@@ -177,34 +160,24 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Ошибка сохранения',
'admin.tabs.addons': 'Дополнения',
'admin.addons.title': 'Дополнения',
'admin.addons.subtitle':
'Включайте или отключайте функции для настройки TREK под себя.',
'admin.addons.subtitle': 'Включайте или отключайте функции для настройки TREK под себя.',
'admin.addons.catalog.memories.name': 'Фото (Immich)',
'admin.addons.catalog.memories.description':
'Делитесь фотографиями из поездок через Immich',
'admin.addons.catalog.memories.description': 'Делитесь фотографиями из поездок через Immich',
'admin.addons.catalog.mcp.name': 'MCP',
'admin.addons.catalog.mcp.description':
'Протокол контекста модели для интеграции с ИИ-ассистентами',
'admin.addons.catalog.mcp.description': 'Протокол контекста модели для интеграции с ИИ-ассистентами',
'admin.addons.catalog.packing.name': 'Списки',
'admin.addons.catalog.packing.description':
'Списки вещей и задачи для ваших поездок',
'admin.addons.catalog.packing.description': 'Списки вещей и задачи для ваших поездок',
'admin.addons.catalog.budget.name': 'Бюджет',
'admin.addons.catalog.budget.description':
'Отслеживайте расходы и планируйте бюджет поездки',
'admin.addons.catalog.budget.description': 'Отслеживайте расходы и планируйте бюджет поездки',
'admin.addons.catalog.documents.name': 'Документы',
'admin.addons.catalog.documents.description':
'Храните и управляйте документами для путешествий',
'admin.addons.catalog.documents.description': 'Храните и управляйте документами для путешествий',
'admin.addons.catalog.vacay.name': 'Vacay',
'admin.addons.catalog.vacay.description':
'Личный планировщик отпусков с календарём',
'admin.addons.catalog.vacay.description': 'Личный планировщик отпусков с календарём',
'admin.addons.catalog.atlas.name': 'Atlas',
'admin.addons.catalog.atlas.description':
'Карта мира с посещёнными странами и статистикой путешествий',
'admin.addons.catalog.atlas.description': 'Карта мира с посещёнными странами и статистикой путешествий',
'admin.addons.catalog.collab.name': 'Collab',
'admin.addons.catalog.collab.description':
'Заметки в реальном времени, опросы и чат для планирования поездок',
'admin.addons.subtitleBefore':
'Включайте или отключайте функции для настройки ',
'admin.addons.catalog.collab.description': 'Заметки в реальном времени, опросы и чат для планирования поездок',
'admin.addons.subtitleBefore': 'Включайте или отключайте функции для настройки ',
'admin.addons.subtitleAfter': ' под себя.',
'admin.addons.enabled': 'Включено',
'admin.addons.disabled': 'Отключено',
@@ -212,10 +185,8 @@ const admin: TranslationStrings = {
'admin.addons.type.global': 'Глобально',
'admin.addons.type.integration': 'Интеграция',
'admin.addons.tripHint': 'Доступно как вкладка внутри каждой поездки',
'admin.addons.globalHint':
'Доступно как отдельный раздел в основной навигации',
'admin.addons.integrationHint':
'Фоновые сервисы и API-интеграции без отдельной страницы',
'admin.addons.globalHint': 'Доступно как отдельный раздел в основной навигации',
'admin.addons.integrationHint': 'Фоновые сервисы и API-интеграции без отдельной страницы',
'admin.addons.toast.updated': 'Дополнение обновлено',
'admin.addons.toast.error': 'Не удалось обновить дополнение',
'admin.addons.noAddons': 'Нет доступных дополнений',
@@ -226,16 +197,14 @@ const admin: TranslationStrings = {
'admin.weather.forecast': 'Прогноз на 16 дней',
'admin.weather.forecastDesc': 'Ранее 5 дней (OpenWeatherMap)',
'admin.weather.climate': 'Исторические климатические данные',
'admin.weather.climateDesc':
'Средние значения за последние 85 лет для дней за пределами 16-дневного прогноза',
'admin.weather.climateDesc': 'Средние значения за последние 85 лет для дней за пределами 16-дневного прогноза',
'admin.weather.requests': '10 000 запросов / день',
'admin.weather.requestsDesc': 'Бесплатно, API-ключ не требуется',
'admin.weather.locationHint':
'Погода основана на первом месте с координатами в каждом дне. Если ни одно место не назначено на день, в качестве ориентира используется любое место из списка.',
'admin.tabs.mcpTokens': 'MCP-доступ',
'admin.mcpTokens.title': 'MCP-доступ',
'admin.mcpTokens.subtitle':
'Управление OAuth-сессиями и API-токенами всех пользователей',
'admin.mcpTokens.subtitle': 'Управление OAuth-сессиями и API-токенами всех пользователей',
'admin.mcpTokens.sectionTitle': 'API-токены',
'admin.mcpTokens.owner': 'Владелец',
'admin.mcpTokens.tokenName': 'Название токена',
@@ -256,8 +225,7 @@ const admin: TranslationStrings = {
'admin.oauthSessions.created': 'Создано',
'admin.oauthSessions.empty': 'Нет активных OAuth-сессий',
'admin.oauthSessions.revokeTitle': 'Отозвать сессию',
'admin.oauthSessions.revokeMessage':
'Эта OAuth-сессия будет немедленно отозвана. Клиент потеряет доступ к MCP.',
'admin.oauthSessions.revokeMessage': 'Эта OAuth-сессия будет немедленно отозвана. Клиент потеряет доступ к MCP.',
'admin.oauthSessions.revokeSuccess': 'Сессия отозвана',
'admin.oauthSessions.revokeError': 'Не удалось отозвать сессию',
'admin.oauthSessions.loadError': 'Не удалось загрузить OAuth-сессии',
@@ -286,23 +254,19 @@ const admin: TranslationStrings = {
'admin.github.error': 'Не удалось загрузить релизы',
'admin.github.by': 'от',
'admin.update.available': 'Доступно обновление',
'admin.update.text':
'Доступна версия TREK {version}. У вас установлена {current}.',
'admin.update.text': 'Доступна версия TREK {version}. У вас установлена {current}.',
'admin.update.button': 'Посмотреть на GitHub',
'admin.update.install': 'Установить обновление',
'admin.update.confirmTitle': 'Установить обновление?',
'admin.update.confirmText':
'TREK будет обновлён с {current} до {version}. Сервер перезапустится автоматически.',
'admin.update.confirmText': 'TREK будет обновлён с {current} до {version}. Сервер перезапустится автоматически.',
'admin.update.dataInfo':
'Все ваши данные (поездки, пользователи, API-ключи, загрузки, Vacay, Atlas, бюджеты) будут сохранены.',
'admin.update.warning':
'Приложение будет кратковременно недоступно во время перезапуска.',
'admin.update.warning': 'Приложение будет кратковременно недоступно во время перезапуска.',
'admin.update.confirm': 'Обновить сейчас',
'admin.update.installing': 'Обновление…',
'admin.update.success': 'Обновление установлено! Сервер перезапускается…',
'admin.update.failed': 'Ошибка обновления',
'admin.update.backupHint':
'Рекомендуем создать резервную копию перед обновлением.',
'admin.update.backupHint': 'Рекомендуем создать резервную копию перед обновлением.',
'admin.update.backupLink': 'Перейти к резервным копиям',
'admin.update.howTo': 'Как обновить',
'admin.update.dockerText':
@@ -312,17 +276,13 @@ const admin: TranslationStrings = {
'admin.notifications.emailPanel.title': 'Email (SMTP)',
'admin.notifications.webhookPanel.title': 'Webhook',
'admin.notifications.inappPanel.title': 'In-App',
'admin.notifications.inappPanel.hint':
'Уведомления в приложении всегда активны и не могут быть отключены глобально.',
'admin.notifications.inappPanel.hint': 'Уведомления в приложении всегда активны и не могут быть отключены глобально.',
'admin.notifications.adminWebhookPanel.title': 'Вебхук администратора',
'admin.notifications.adminWebhookPanel.hint':
'Этот вебхук используется исключительно для уведомлений администратора (например, оповещения о версиях). Он независим от пользовательских вебхуков и отправляется автоматически при наличии URL.',
'admin.notifications.adminWebhookPanel.saved':
'URL вебхука администратора сохранён',
'admin.notifications.adminWebhookPanel.testSuccess':
'Тестовый вебхук успешно отправлен',
'admin.notifications.adminWebhookPanel.testFailed':
'Ошибка тестового вебхука',
'admin.notifications.adminWebhookPanel.saved': 'URL вебхука администратора сохранён',
'admin.notifications.adminWebhookPanel.testSuccess': 'Тестовый вебхук успешно отправлен',
'admin.notifications.adminWebhookPanel.testFailed': 'Ошибка тестового вебхука',
'admin.notifications.adminWebhookPanel.alwaysOnHint':
'Вебхук администратора отправляется автоматически при наличии URL',
'admin.notifications.ntfy': 'Ntfy',
@@ -340,17 +300,12 @@ const admin: TranslationStrings = {
'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.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.testSuccess': 'Тестовое Ntfy успешно отправлено',
'admin.notifications.adminNtfyPanel.testFailed': 'Ошибка отправки тестового Ntfy',
'admin.notifications.adminNtfyPanel.alwaysOnHint':
'Ntfy администратора всегда отправляется при наличии настроенной темы',
'admin.notifications.adminNotificationsHint':
@@ -358,17 +313,14 @@ const admin: TranslationStrings = {
'admin.notifications.tripReminders.title': 'Напоминания о поездках',
'admin.notifications.tripReminders.hint':
'Отправляет напоминание перед началом поездки (необходимо указать дни напоминания в параметрах поездки).',
'admin.notifications.tripReminders.enabled':
'Напоминания о поездках включены',
'admin.notifications.tripReminders.disabled':
'Напоминания о поездках отключены',
'admin.notifications.tripReminders.enabled': 'Напоминания о поездках включены',
'admin.notifications.tripReminders.disabled': 'Напоминания о поездках отключены',
'admin.tabs.notifications': 'Уведомления',
'admin.addons.catalog.journey.name': 'Путешествие',
'admin.addons.catalog.journey.description':
'Отслеживание поездок и дневник путешествий с отметками, фото и ежедневными историями',
'admin.passkey.title': 'Вход по passkey',
'admin.passkey.cardHint':
'Разрешите пользователям входить с помощью passkeys (WebAuthn). По умолчанию выключено.',
'admin.passkey.cardHint': 'Разрешите пользователям входить с помощью passkeys (WebAuthn). По умолчанию выключено.',
'admin.passkey.login': 'Включить вход по passkey',
'admin.passkey.loginHint':
'Показывать вариант «Войти с помощью passkey» и разрешить пользователям регистрировать passkeys в своих настройках.',
@@ -386,11 +338,13 @@ const admin: TranslationStrings = {
'admin.passkey.resetConfirm': 'Удалить все passkeys пользователя {name}?',
'admin.passkey.resetDone': 'Удалено passkeys: {count}',
'admin.defaultSettings.mapProvider': 'Картографический движок',
'admin.defaultSettings.mapProviderHint': 'Карта по умолчанию для всех на этом сервере. Каждый пользователь по-прежнему может изменить её в своих настройках.',
'admin.defaultSettings.mapProviderHint':
'Карта по умолчанию для всех на этом сервере. Каждый пользователь по-прежнему может изменить её в своих настройках.',
'admin.defaultSettings.providerLeaflet': 'Стандартная (бесплатно)',
'admin.defaultSettings.providerMapbox': 'Mapbox (3D)',
'admin.defaultSettings.mapboxToken': 'Общий токен Mapbox',
'admin.defaultSettings.mapboxTokenHint': 'Используется для каждого пользователя, который не ввёл собственный токен — так весь сервер получает Mapbox без необходимости делиться ключом по отдельности. Хранится в зашифрованном виде.',
'admin.defaultSettings.mapboxTokenHint':
'Используется для каждого пользователя, который не ввёл собственный токен — так весь сервер получает Mapbox без необходимости делиться ключом по отдельности. Хранится в зашифрованном виде.',
'admin.defaultSettings.mapboxStyle': 'Стиль карты',
'admin.defaultSettings.mapboxStylePlaceholder': 'Выберите стиль…',
'admin.defaultSettings.mapbox3d': '3D-здания и рельеф',
+1 -2
View File
@@ -9,8 +9,7 @@ const atlas: TranslationStrings = {
'atlas.visitedCountries': 'Посещённые страны',
'atlas.cities': 'Города',
'atlas.noData': 'Данных о поездках пока нет',
'atlas.noDataHint':
'Создайте поездку и добавьте места, чтобы увидеть карту мира',
'atlas.noDataHint': 'Создайте поездку и добавьте места, чтобы увидеть карту мира',
'atlas.lastTrip': 'Последняя поездка',
'atlas.nextTrip': 'Следующая поездка',
'atlas.daysLeft': 'дней осталось',
+5 -10
View File
@@ -12,8 +12,7 @@ const backup: TranslationStrings = {
'backup.createFirst': 'Создать первую копию',
'backup.download': 'Скачать',
'backup.restore': 'Восстановить',
'backup.confirm.restore':
'Восстановить копию «{name}»?\n\nВсе текущие данные будут заменены данными из копии.',
'backup.confirm.restore': 'Восстановить копию «{name}»?\n\nВсе текущие данные будут заменены данными из копии.',
'backup.confirm.uploadRestore':
'Загрузить и восстановить файл копии «{name}»?\n\nВсе текущие данные будут перезаписаны.',
'backup.confirm.delete': 'Удалить копию «{name}»?',
@@ -31,15 +30,13 @@ const backup: TranslationStrings = {
'backup.auto.title': 'Автокопирование',
'backup.auto.subtitle': 'Автоматическое резервное копирование по расписанию',
'backup.auto.enable': 'Включить автокопирование',
'backup.auto.enableHint':
'Резервные копии будут создаваться автоматически по выбранному расписанию',
'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.dayOfMonthHint': 'Ограничено 1–28 для совместимости со всеми месяцами',
'backup.auto.scheduleSummary': 'Расписание',
'backup.auto.summaryDaily': 'Каждый день в {hour}:00',
'backup.auto.summaryWeekly': 'Каждый {day} в {hour}:00',
@@ -48,8 +45,7 @@ const backup: TranslationStrings = {
'backup.auto.envLockedHint':
'Автокопирование настроено через переменные окружения Docker. Чтобы изменить параметры, обновите docker-compose.yml и перезапустите контейнер.',
'backup.auto.copyEnv': 'Скопировать переменные окружения Docker',
'backup.auto.envCopied':
'Переменные окружения Docker скопированы в буфер обмена',
'backup.auto.envCopied': 'Переменные окружения Docker скопированы в буфер обмена',
'backup.auto.keepLabel': 'Удалять старые копии через',
'backup.dow.sunday': 'Вс',
'backup.dow.monday': 'Пн',
@@ -71,8 +67,7 @@ const backup: TranslationStrings = {
'backup.restoreConfirmTitle': 'Восстановить копию?',
'backup.restoreWarning':
'Все текущие данные (поездки, места, пользователи, загрузки) будут безвозвратно заменены данными из копии. Это действие нельзя отменить.',
'backup.restoreTip':
'Совет: создайте резервную копию текущего состояния перед восстановлением.',
'backup.restoreTip': 'Совет: создайте резервную копию текущего состояния перед восстановлением.',
'backup.restoreConfirm': 'Да, восстановить',
};
export default backup;
+82 -78
View File
@@ -4,8 +4,7 @@ const budget: TranslationStrings = {
'budget.title': 'Бюджет',
'budget.exportCsv': 'Экспорт CSV',
'budget.emptyTitle': 'Бюджет ещё не создан',
'budget.emptyText':
'Создайте категории и записи для планирования бюджета поездки',
'budget.emptyText': 'Создайте категории и записи для планирования бюджета поездки',
'budget.emptyPlaceholder': 'Введите название категории...',
'budget.createCategory': 'Создать категорию',
'budget.category': 'Категория',
@@ -26,10 +25,8 @@ const budget: TranslationStrings = {
'budget.totalBudget': 'Общий бюджет',
'budget.byCategory': 'По категориям',
'budget.editTooltip': 'Нажмите для редактирования',
'budget.linkedToReservation':
'Связано с бронированием — редактируйте название там',
'budget.confirm.deleteCategory':
'Вы уверены, что хотите удалить категорию «{name}» с {count} записями?',
'budget.linkedToReservation': 'Связано с бронированием — редактируйте название там',
'budget.confirm.deleteCategory': 'Вы уверены, что хотите удалить категорию «{name}» с {count} записями?',
'budget.deleteCategory': 'Удалить категорию',
'budget.perPerson': 'На человека',
'budget.paid': 'Оплачено',
@@ -40,78 +37,85 @@ const budget: TranslationStrings = {
'Нажмите на аватар участника в строке бюджета, чтобы отметить его зелёным — это значит, что он заплатил. Взаиморасчёт покажет, кто кому и сколько должен.',
'budget.netBalances': 'Чистые балансы',
'budget.categoriesLabel': 'категорий',
"costs.you": "Вы",
"costs.youShort": "В",
"costs.youLower": "вы",
"costs.youOwe": "Вы должны",
"costs.youOweSub": "Вы должны заплатить другим",
"costs.youreOwed": "Вам должны",
"costs.youreOwedSub": "Другие должны заплатить вам",
"costs.totalSpend": "Общие расходы поездки",
"costs.totalSpendSub": "По всем участникам",
"costs.to": "Кому",
"costs.from": "От",
"costs.allSettled": "У вас всё рассчитано",
"costs.nothingOwed": "Вам ничего не должны",
"costs.yourShare": "Ваша доля",
"costs.youPaid": "Вы заплатили",
"costs.expenses": "Расходы",
"costs.entries": "{count} записей",
"costs.searchPlaceholder": "Поиск расходов…",
"costs.filter.all": "Все",
"costs.filter.mine": "Оплачено мной",
"costs.filter.owed": "Мне должны",
"costs.addExpense": "Добавить расход",
"costs.editExpense": "Изменить расход",
"costs.noMatch": "Нет расходов по вашему запросу.",
"costs.emptyText": "Расходов пока нет. Добавьте первый.",
"costs.spent": "потрачено {amount}",
"costs.noDate": "Без даты",
"costs.noOnePaid": "Пока никто не заплатил",
"costs.youLent": "вы одолжили {amount}",
"costs.youBorrowed": "вы заняли {amount}",
"costs.settleUp": "Рассчитаться",
"costs.history": "История",
"costs.everyoneSquare": "Все в расчёте",
"costs.nothingOutstanding": "Сейчас нет неоплаченных платежей.",
"costs.pay": "платит",
"costs.pays": "платит",
"costs.settle": "Рассчитать",
"costs.balances": "Балансы",
"costs.byCategory": "По категориям",
"costs.noCategories": "Расходов пока нет.",
"costs.settleHistory": "История расчётов",
"costs.noSettlements": "Расчётов пока нет.",
"costs.paymentsSettled": "Рассчитано платежей: {count}",
"costs.paid": "оплачено",
"costs.undo": "Отменить",
"costs.whatFor": "За что это было?",
"costs.namePlaceholder": "напр. ужин, сувениры, бензин…",
"costs.totalAmount": "Общая сумма",
"costs.currency": "Валюта",
"costs.day": "День",
"costs.rateLabel": "1 {from} в {to}",
"costs.category": "Категория",
"costs.whoPaid": "Кто заплатил?",
"costs.splitBetween": "Поделить поровну между",
"costs.pickSomeone": "Выберите хотя бы одного человека для разделения.",
"costs.splitSummary": "Разделено на {count} · по {amount}",
"costs.cat.accommodation": "Проживание",
"costs.cat.food": "Еда и напитки",
"costs.cat.groceries": "Продукты",
"costs.cat.transport": "Транспорт",
"costs.cat.flights": "Авиаперелёты",
"costs.cat.activities": "Развлечения",
"costs.cat.sightseeing": "Достопримечательности",
"costs.cat.shopping": "Покупки",
"costs.cat.fees": "Сборы и билеты",
"costs.cat.health": "Здоровье",
"costs.cat.tips": "Чаевые",
"costs.cat.other": "Прочее",
"costs.daysCount": "{count} дней",
"costs.travelers": "{count} путешественников",
"costs.liveRate": "актуальный курс",
"costs.settleAll": "Рассчитать всё",
'costs.you': 'Вы',
'costs.youShort': 'В',
'costs.youLower': 'вы',
'costs.youOwe': 'Вы должны',
'costs.youOweSub': 'Вы должны заплатить другим',
'costs.youreOwed': 'Вам должны',
'costs.youreOwedSub': 'Другие должны заплатить вам',
'costs.totalSpend': 'Общие расходы поездки',
'costs.totalSpendSub': 'По всем участникам',
'costs.to': 'Кому',
'costs.from': 'От',
'costs.allSettled': 'У вас всё рассчитано',
'costs.nothingOwed': 'Вам ничего не должны',
'costs.yourShare': 'Ваша доля',
'costs.youPaid': 'Вы заплатили',
'costs.expenses': 'Расходы',
'costs.entries': '{count} записей',
'costs.searchPlaceholder': 'Поиск расходов…',
'costs.filter.all': 'Все',
'costs.filter.mine': 'Оплачено мной',
'costs.filter.owed': 'Мне должны',
'costs.addExpense': 'Добавить расход',
'costs.editExpense': 'Изменить расход',
'costs.noMatch': 'Нет расходов по вашему запросу.',
'costs.emptyText': 'Расходов пока нет. Добавьте первый.',
'costs.spent': 'потрачено {amount}',
'costs.noDate': 'Без даты',
'costs.noOnePaid': 'Пока никто не заплатил',
'costs.youLent': 'вы одолжили {amount}',
'costs.youBorrowed': 'вы заняли {amount}',
'costs.settleUp': 'Рассчитаться',
'costs.history': 'История',
'costs.everyoneSquare': 'Все в расчёте',
'costs.nothingOutstanding': 'Сейчас нет неоплаченных платежей.',
'costs.pay': 'платит',
'costs.pays': 'платит',
'costs.settle': 'Рассчитать',
'costs.balances': 'Балансы',
'costs.byCategory': 'По категориям',
'costs.noCategories': 'Расходов пока нет.',
'costs.settleHistory': 'История расчётов',
'costs.noSettlements': 'Расчётов пока нет.',
'costs.paymentsSettled': 'Рассчитано платежей: {count}',
'costs.paid': 'оплачено',
'costs.undo': 'Отменить',
'costs.whatFor': 'За что это было?',
'costs.namePlaceholder': 'напр. ужин, сувениры, бензин…',
'costs.totalAmount': 'Общая сумма',
'costs.currency': 'Валюта',
'costs.day': 'День',
'costs.rateLabel': '1 {from} в {to}',
'costs.category': 'Категория',
'costs.whoPaid': 'Кто заплатил?',
'costs.splitBetween': 'Поделить поровну между',
'costs.pickSomeone': 'Выберите хотя бы одного человека для разделения.',
'costs.splitSummary': 'Разделено на {count} · по {amount}',
'costs.cat.accommodation': 'Проживание',
'costs.cat.food': 'Еда и напитки',
'costs.cat.groceries': 'Продукты',
'costs.cat.transport': 'Транспорт',
'costs.cat.flights': 'Авиаперелёты',
'costs.cat.activities': 'Развлечения',
'costs.cat.sightseeing': 'Достопримечательности',
'costs.cat.shopping': 'Покупки',
'costs.cat.fees': 'Сборы и билеты',
'costs.cat.health': 'Здоровье',
'costs.cat.tips': 'Чаевые',
'costs.cat.other': 'Прочее',
'costs.daysCount': '{count} дней',
'costs.travelers': '{count} путешественников',
'costs.liveRate': 'актуальный курс',
'costs.settleAll': 'Рассчитать всё',
'costs.payment': 'Платёж',
'costs.editPayment': 'Изменить платёж',
'costs.addPayment': 'Добавить платёж',
'costs.unfinished': 'Не завершено',
'costs.unfinishedHint': 'Только в сумме — ещё не урегулировано',
'costs.tapToInclude': 'Нажмите, чтобы добавить',
'costs.amount': 'Сумма',
};
export default budget;
+1 -2
View File
@@ -13,8 +13,7 @@ const categories: TranslationStrings = {
'categories.defaultName': 'Категория',
'categories.update': 'Обновить',
'categories.create': 'Создать',
'categories.confirm.delete':
'Удалить категорию? Места в этой категории не будут удалены.',
'categories.confirm.delete': 'Удалить категорию? Места в этой категории не будут удалены.',
'categories.toast.loadError': 'Не удалось загрузить категории',
'categories.toast.nameRequired': 'Введите название',
'categories.toast.updated': 'Категория обновлена',
+2 -4
View File
@@ -9,14 +9,12 @@ const collab: TranslationStrings = {
'collab.whatsNext.tomorrow': 'Завтра',
'collab.whatsNext.empty': 'Нет предстоящих активностей',
'collab.whatsNext.until': 'до',
'collab.whatsNext.emptyHint':
'Активности со временем будут отображаться здесь',
'collab.whatsNext.emptyHint': 'Активности со временем будут отображаться здесь',
'collab.chat.send': 'Отправить',
'collab.chat.placeholder': 'Введите сообщение...',
'collab.chat.empty': 'Начните разговор',
'collab.chat.emptyHint': 'Сообщения видны всем участникам поездки',
'collab.chat.emptyDesc':
'Делитесь идеями, планами и новостями с вашей группой',
'collab.chat.emptyDesc': 'Делитесь идеями, планами и новостями с вашей группой',
'collab.chat.today': 'Сегодня',
'collab.chat.yesterday': 'Вчера',
'collab.chat.deletedMessage': 'удалил(а) сообщение',
+4 -8
View File
@@ -20,8 +20,7 @@ const dashboard: TranslationStrings = {
'dashboard.timezoneCustomTzPlaceholder': 'напр. America/New_York',
'dashboard.timezoneCustomAdd': 'Добавить',
'dashboard.timezoneCustomErrorEmpty': 'Введите идентификатор часового пояса',
'dashboard.timezoneCustomErrorInvalid':
'Неверный часовой пояс. Используйте формат Europe/Berlin',
'dashboard.timezoneCustomErrorInvalid': 'Неверный часовой пояс. Используйте формат Europe/Berlin',
'dashboard.timezoneCustomErrorDuplicate': 'Уже добавлен',
'dashboard.emptyTitle': 'Нет поездок',
'dashboard.emptyText': 'Создайте свою первую поездку и начните планировать!',
@@ -55,8 +54,7 @@ const dashboard: TranslationStrings = {
'dashboard.toast.restoreError': 'Не удалось восстановить поездку',
'dashboard.toast.copied': 'Поездка скопирована!',
'dashboard.toast.copyError': 'Не удалось скопировать поездку',
'dashboard.confirm.delete':
'Удалить поездку «{title}»? Все места и планы будут безвозвратно удалены.',
'dashboard.confirm.delete': 'Удалить поездку «{title}»? Все места и планы будут безвозвратно удалены.',
'dashboard.editTrip': 'Редактировать поездку',
'dashboard.createTrip': 'Создать новую поездку',
'dashboard.tripTitle': 'Название',
@@ -66,10 +64,8 @@ const dashboard: TranslationStrings = {
'dashboard.startDate': 'Дата начала',
'dashboard.endDate': 'Дата окончания',
'dashboard.dayCount': 'Количество дней',
'dashboard.dayCountHint':
'Сколько дней планировать, если даты поездки не указаны.',
'dashboard.noDateHint':
'Дата не указана — будет создано 7 дней по умолчанию. Вы можете изменить это в любое время.',
'dashboard.dayCountHint': 'Сколько дней планировать, если даты поездки не указаны.',
'dashboard.noDateHint': 'Дата не указана — будет создано 7 дней по умолчанию. Вы можете изменить это в любое время.',
'dashboard.coverImage': 'Обложка',
'dashboard.addCoverImage': 'Добавить обложку',
'dashboard.addMembers': 'Попутчики',
+1 -2
View File
@@ -7,8 +7,7 @@ const day: TranslationStrings = {
'day.sunrise': 'Восход',
'day.sunset': 'Закат',
'day.hourlyForecast': 'Почасовой прогноз',
'day.climateHint':
'Исторические средние — реальный прогноз доступен за 16 дней до этой даты.',
'day.climateHint': 'Исторические средние — реальный прогноз доступен за 16 дней до этой даты.',
'day.noWeather': 'Данные о погоде недоступны. Добавьте место с координатами.',
'day.overview': 'Обзор дня',
'day.accommodation': 'Жильё',
+6 -12
View File
@@ -17,30 +17,24 @@ const dayplan: TranslationStrings = {
'dayplan.optimize': 'Оптимизировать',
'dayplan.optimized': 'Маршрут оптимизирован',
'dayplan.routeError': 'Не удалось рассчитать маршрут',
'dayplan.toast.needTwoPlaces':
'Для оптимизации маршрута нужно минимум два места',
'dayplan.toast.needTwoPlaces': 'Для оптимизации маршрута нужно минимум два места',
'dayplan.toast.routeOptimized': 'Маршрут оптимизирован',
'dayplan.toast.routeOptimizedFromHotel':
'Маршрут оптимизирован от места проживания',
'dayplan.toast.noGeoPlaces':
'Не найдено мест с координатами для расчёта маршрута',
'dayplan.toast.routeOptimizedFromHotel': 'Маршрут оптимизирован от места проживания',
'dayplan.toast.noGeoPlaces': 'Не найдено мест с координатами для расчёта маршрута',
'dayplan.confirmed': 'Подтверждено',
'dayplan.pendingRes': 'Ожидание',
'dayplan.pdf': 'PDF',
'dayplan.pdfTooltip': 'Экспортировать план дня в PDF',
'dayplan.pdfError': 'Ошибка экспорта PDF',
'dayplan.cannotReorderTransport':
'Бронирования с фиксированным временем нельзя перемещать',
'dayplan.cannotReorderTransport': 'Бронирования с фиксированным временем нельзя перемещать',
'dayplan.confirmRemoveTimeTitle': 'Удалить время?',
'dayplan.confirmRemoveTimeBody':
'У этого места фиксированное время ({time}). При перемещении время будет удалено, и станет доступна свободная сортировка.',
'dayplan.confirmRemoveTimeAction': 'Удалить время и переместить',
'dayplan.confirmDeleteNoteTitle': 'Удалить заметку?',
'dayplan.confirmDeleteNoteBody': 'Эта заметка будет удалена безвозвратно.',
'dayplan.cannotDropOnTimed':
'Элементы нельзя размещать между записями с фиксированным временем',
'dayplan.cannotBreakChronology':
'Это нарушит хронологический порядок запланированных элементов и бронирований',
'dayplan.cannotDropOnTimed': 'Элементы нельзя размещать между записями с фиксированным временем',
'dayplan.cannotBreakChronology': 'Это нарушит хронологический порядок запланированных элементов и бронирований',
'dayplan.mobile.addPlace': 'Добавить место',
'dayplan.mobile.searchPlaces': 'Поиск мест...',
'dayplan.mobile.allAssigned': 'Все места распределены',
+1 -2
View File
@@ -55,8 +55,7 @@ const ru: NotificationLocale = {
body: 'Мы получили запрос на сброс пароля вашего аккаунта TREK. Нажмите кнопку ниже, чтобы установить новый пароль.',
ctaIntro: 'Сбросить пароль',
expiry: 'Ссылка действительна 60 минут.',
ignore:
'Если вы не запрашивали сброс — просто проигнорируйте это письмо, пароль останется прежним.',
ignore: 'Если вы не запрашивали сброс — просто проигнорируйте это письмо, пароль останется прежним.',
},
};
+4 -8
View File
@@ -13,8 +13,7 @@ const files: TranslationStrings = {
'files.uploadError': 'Ошибка загрузки',
'files.dropzone': 'Перетащите файлы сюда',
'files.dropzoneHint': 'или нажмите для выбора',
'files.allowedTypes':
'Изображения, PDF, DOC, DOCX, XLS, XLSX, TXT, CSV · Макс. 50 МБ',
'files.allowedTypes': 'Изображения, PDF, DOC, DOCX, XLS, XLSX, TXT, CSV · Макс. 50 МБ',
'files.uploading': 'Загрузка...',
'files.filterAll': 'Все',
'files.filterPdf': 'PDF',
@@ -32,8 +31,7 @@ const files: TranslationStrings = {
'files.sourceBooking': 'Бронирование',
'files.sourceTransport': 'Транспорт',
'files.attach': 'Прикрепить',
'files.pasteHint':
'Также можно вставить изображения из буфера обмена (Ctrl+V)',
'files.pasteHint': 'Также можно вставить изображения из буфера обмена (Ctrl+V)',
'files.trash': 'Корзина',
'files.trashEmpty': 'Корзина пуста',
'files.emptyTrash': 'Очистить корзину',
@@ -53,10 +51,8 @@ const files: TranslationStrings = {
'files.toast.assigned': 'Файл назначен',
'files.toast.assignError': 'Ошибка назначения',
'files.toast.restoreError': 'Ошибка восстановления',
'files.confirm.permanentDelete':
'Безвозвратно удалить этот файл? Это действие нельзя отменить.',
'files.confirm.emptyTrash':
'Безвозвратно удалить все файлы из корзины? Это действие нельзя отменить.',
'files.confirm.permanentDelete': 'Безвозвратно удалить этот файл? Это действие нельзя отменить.',
'files.confirm.emptyTrash': 'Безвозвратно удалить все файлы из корзины? Это действие нельзя отменить.',
'files.noteLabel': 'Заметка',
'files.notePlaceholder': 'Добавить заметку...',
};
+14 -28
View File
@@ -14,8 +14,7 @@ const journey: TranslationStrings = {
'journey.createError': 'Не удалось создать путешествие',
'journey.deleteError': 'Не удалось удалить путешествие',
'journey.deleteConfirmTitle': 'Удалить',
'journey.deleteConfirmMessage':
'Удалить «{title}»? Это действие нельзя отменить.',
'journey.deleteConfirmMessage': 'Удалить «{title}»? Это действие нельзя отменить.',
'journey.deleteConfirmGeneric': 'Вы уверены, что хотите удалить это?',
'journey.notFound': 'Путешествие не найдено',
'journey.photos': 'Фото',
@@ -46,30 +45,25 @@ const journey: TranslationStrings = {
'journey.editor.titlePlaceholder': 'Дайте название этому моменту...',
'journey.editor.bodyPlaceholder': 'Расскажите историю этого дня...',
'journey.editor.placePlaceholder': 'Местоположение (необязательно)',
'journey.editor.tagsPlaceholder':
'Теги: скрытая жемчужина, лучшая еда, стоит вернуться...',
'journey.editor.tagsPlaceholder': 'Теги: скрытая жемчужина, лучшая еда, стоит вернуться...',
'journey.visibility.private': 'Приватный',
'journey.visibility.shared': 'Общий',
'journey.visibility.public': 'Публичный',
'journey.emptyState.title': 'Ваша история начинается здесь',
'journey.emptyState.subtitle':
'Отметьтесь в месте или напишите первую запись в дневник',
'journey.frontpage.subtitle':
'Превращайте поездки в истории, которые вы никогда не забудете',
'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.createNewSub': 'Выберите поездки, пишите истории, делитесь приключениями',
'journey.frontpage.live': 'В эфире',
'journey.frontpage.synced': 'Синхронизировано',
'journey.frontpage.continueWriting': 'Продолжить писать',
'journey.frontpage.updated': 'Обновлено {time}',
'journey.frontpage.suggestionLabel': 'Поездка только что завершилась',
'journey.frontpage.suggestionText':
'Превратите <strong>{title}</strong> в путешествие',
'journey.frontpage.suggestionText': 'Превратите <strong>{title}</strong> в путешествие',
'journey.frontpage.dismiss': 'Скрыть',
'journey.frontpage.journeyName': 'Название путешествия',
'journey.frontpage.namePlaceholder': 'напр. Юго-Восточная Азия 2026',
@@ -84,11 +78,9 @@ const journey: TranslationStrings = {
'journey.detail.newEntry': 'Новая запись',
'journey.detail.editEntry': 'Редактировать запись',
'journey.detail.noEntries': 'Пока нет записей',
'journey.detail.noEntriesHint':
'Добавьте поездку, чтобы начать с шаблонных записей',
'journey.detail.noEntriesHint': 'Добавьте поездку, чтобы начать с шаблонных записей',
'journey.detail.noPhotos': 'Пока нет фото',
'journey.detail.noPhotosHint':
'Загрузите фото в записи или просмотрите библиотеку Immich/Synology',
'journey.detail.noPhotosHint': 'Загрузите фото в записи или просмотрите библиотеку Immich/Synology',
'journey.detail.journeyStats': 'Статистика путешествия',
'journey.detail.syncedTrips': 'Синхронизированные поездки',
'journey.detail.noTripsLinked': 'Пока нет привязанных поездок',
@@ -109,14 +101,12 @@ const journey: TranslationStrings = {
'journey.verdict.couldBeBetter': 'Могло быть лучше',
'journey.synced.places': 'мест',
'journey.synced.synced': 'синхронизировано',
'journey.editor.discardChangesConfirm':
'У вас есть несохранённые изменения. Отменить?',
'journey.editor.discardChangesConfirm': 'У вас есть несохранённые изменения. Отменить?',
'journey.editor.uploadFailed': 'Не удалось загрузить фото',
'journey.editor.uploadPhotos': 'Загрузить фото',
'journey.editor.uploading': 'Загрузка...',
'journey.editor.uploadingProgress': 'Загрузка {done}/{total}…',
'journey.editor.uploadPartialFailed':
'{failed} из {total} фото не удалось загрузить — сохраните снова для повтора',
'journey.editor.uploadPartialFailed': '{failed} из {total} фото не удалось загрузить — сохраните снова для повтора',
'journey.editor.fromGallery': 'Из галереи',
'journey.editor.allPhotosAdded': 'Все фото уже добавлены',
'journey.editor.writeStory': 'Напишите свою историю...',
@@ -195,12 +185,10 @@ const journey: TranslationStrings = {
'journey.settings.reopenJourney': 'Восстановить путешествие',
'journey.settings.archived': 'Путешествие архивировано',
'journey.settings.reopened': 'Путешествие возобновлено',
'journey.settings.endDescription':
'Скрывает значок «В эфире». Вы можете возобновить в любое время.',
'journey.settings.endDescription': 'Скрывает значок «В эфире». Вы можете возобновить в любое время.',
'journey.settings.delete': 'Удалить',
'journey.settings.deleteJourney': 'Удалить путешествие',
'journey.settings.deleteMessage':
'Удалить «{title}»? Все записи и фото будут потеряны.',
'journey.settings.deleteMessage': 'Удалить «{title}»? Все записи и фото будут потеряны.',
'journey.settings.saved': 'Настройки сохранены',
'journey.settings.saveFailed': 'Не удалось сохранить',
'journey.settings.coverUpdated': 'Обложка обновлена',
@@ -211,11 +199,9 @@ const journey: TranslationStrings = {
'journey.photosUploadFailed': 'Некоторые фото не удалось загрузить',
'journey.photosAdded': '{count} фото добавлено',
'journey.public.notFound': 'Не найдено',
'journey.public.notFoundMessage':
'Это путешествие не существует или ссылка устарела.',
'journey.public.notFoundMessage': 'Это путешествие не существует или ссылка устарела.',
'journey.public.readOnly': 'Только для чтения · Публичное путешествие',
'journey.public.tagline':
'Инструмент планирования и исследования путешествий',
'journey.public.tagline': 'Инструмент планирования и исследования путешествий',
'journey.public.sharedVia': 'Опубликовано через',
'journey.public.madeWith': 'Сделано с помощью',
'journey.pdf.journeyBook': 'Книга путешествия',
+10 -20
View File
@@ -21,8 +21,7 @@ const login: TranslationStrings = {
'login.features.filesDesc': 'Загружайте и управляйте документами',
'login.features.routes': 'Умные маршруты',
'login.features.routesDesc': 'Автооптимизация и экспорт в Google Maps',
'login.selfHosted':
'Самостоятельный хостинг · Открытый код · Ваши данные остаются у вас',
'login.selfHosted': 'Самостоятельный хостинг · Открытый код · Ваши данные остаются у вас',
'login.title': 'Вход',
'login.subtitle': 'С возвращением',
'login.signingIn': 'Вход…',
@@ -30,8 +29,7 @@ const login: TranslationStrings = {
'login.createAdmin': 'Создать аккаунт администратора',
'login.createAdminHint': 'Настройте первый аккаунт администратора для TREK.',
'login.setNewPassword': 'Установить новый пароль',
'login.setNewPasswordHint':
'Вы должны сменить пароль, прежде чем продолжить.',
'login.setNewPasswordHint': 'Вы должны сменить пароль, прежде чем продолжить.',
'login.createAccount': 'Создать аккаунт',
'login.createAccountHint': 'Зарегистрируйте новый аккаунт.',
'login.creating': 'Создание…',
@@ -40,15 +38,13 @@ const login: TranslationStrings = {
'login.register': 'Регистрация',
'login.emailPlaceholder': 'ваш@email.com',
'login.username': 'Имя пользователя',
'login.oidc.registrationDisabled':
'Регистрация отключена. Обратитесь к администратору.',
'login.oidc.registrationDisabled': 'Регистрация отключена. Обратитесь к администратору.',
'login.oidc.noEmail': 'Провайдер не предоставил адрес эл. почты.',
'login.mfaTitle': 'Двухфакторная аутентификация',
'login.mfaSubtitle': 'Введите 6-значный код из приложения-аутентификатора.',
'login.mfaCodeLabel': 'Код подтверждения',
'login.mfaCodeRequired': 'Введите код из приложения-аутентификатора.',
'login.mfaHint':
'Откройте Google Authenticator, Authy или другое TOTP-приложение.',
'login.mfaHint': 'Откройте Google Authenticator, Authy или другое TOTP-приложение.',
'login.mfaBack': '← Назад к входу',
'login.mfaVerify': 'Подтвердить',
'login.invalidInviteLink': 'Недействительная или истёкшая ссылка-приглашение',
@@ -72,27 +68,21 @@ const login: TranslationStrings = {
'login.passwordsDontMatch': 'Пароли не совпадают',
'login.mfaCode': 'Код 2FA',
'login.resetPasswordTitle': 'Задайте новый пароль',
'login.resetPasswordBody':
'Выберите надёжный пароль, который вы здесь ещё не использовали. Минимум 8 символов.',
'login.resetPasswordMfaBody':
'Введите код 2FA или резервный код, чтобы завершить сброс.',
'login.resetPasswordBody': 'Выберите надёжный пароль, который вы здесь ещё не использовали. Минимум 8 символов.',
'login.resetPasswordMfaBody': 'Введите код 2FA или резервный код, чтобы завершить сброс.',
'login.resetPasswordSubmit': 'Сбросить пароль',
'login.resetPasswordVerify': 'Проверить и сбросить',
'login.resetPasswordSuccessTitle': 'Пароль обновлён',
'login.resetPasswordSuccessBody': 'Теперь вы можете войти с новым паролем.',
'login.resetPasswordInvalidLink': 'Неверная ссылка сброса',
'login.resetPasswordInvalidLinkBody':
'Ссылка отсутствует или повреждена. Запросите новую, чтобы продолжить.',
'login.resetPasswordFailed':
'Сброс не удался. Возможно, срок действия ссылки истёк.',
'login.resetPasswordInvalidLinkBody': 'Ссылка отсутствует или повреждена. Запросите новую, чтобы продолжить.',
'login.resetPasswordFailed': 'Сброс не удался. Возможно, срок действия ссылки истёк.',
'login.oidc.tokenFailed': 'Аутентификация не удалась.',
'login.oidc.invalidState': 'Недействительная сессия. Попробуйте снова.',
'login.demoFailed': 'Ошибка демо-входа',
'login.oidcSignIn': 'Войти через {name}',
'login.oidcOnly':
'Вход по паролю отключён. Используйте вашего провайдера SSO для входа.',
'login.oidcLoggedOut':
'Вы вышли из системы. Войдите снова через вашего провайдера SSO.',
'login.oidcOnly': 'Вход по паролю отключён. Используйте вашего провайдера SSO для входа.',
'login.oidcLoggedOut': 'Вы вышли из системы. Войдите снова через вашего провайдера SSO.',
'login.demoHint': 'Попробуйте демо — регистрация не требуется',
'login.passkey.signIn': 'Войти с помощью passkey',
'login.passkey.failed': 'Не удалось войти с помощью passkey. Попробуйте ещё раз.',
+5 -10
View File
@@ -3,8 +3,7 @@ import type { TranslationStrings } from '../types';
const memories: TranslationStrings = {
'memories.title': 'Фото',
'memories.notConnected': 'Immich не подключён',
'memories.notConnectedHint':
'Подключите Immich в настройках, чтобы видеть фотографии из поездок.',
'memories.notConnectedHint': 'Подключите Immich в настройках, чтобы видеть фотографии из поездок.',
'memories.notConnectedMultipleHint':
'Подключите одного из этих фотопровайдеров: {provider_names} в Настройках, чтобы добавлять фотографии к этому путешествию.',
'memories.noDates': 'Добавьте даты поездки для загрузки фотографий.',
@@ -15,8 +14,7 @@ const memories: TranslationStrings = {
'memories.sharePhotos': 'Поделиться фото',
'memories.sharing': 'Общий доступ',
'memories.reviewTitle': 'Проверьте ваши фото',
'memories.reviewHint':
'Нажмите на фото, чтобы исключить его из общего доступа.',
'memories.reviewHint': 'Нажмите на фото, чтобы исключить его из общего доступа.',
'memories.shareCount': 'Поделиться ({count} фото)',
'memories.providerUrl': 'URL сервера',
'memories.providerApiKey': 'API-ключ',
@@ -25,8 +23,7 @@ const memories: TranslationStrings = {
'memories.providerOTP': 'Код MFA (если включён)',
'memories.skipSSLVerification': 'Пропустить проверку SSL-сертификата',
'memories.immichAutoUpload': 'Дублировать фото journey в Immich при загрузке',
'memories.providerUrlHintSynology':
'Включите путь приложения Photos в URL, например https://nas:5001/photo',
'memories.providerUrlHintSynology': 'Включите путь приложения Photos в URL, например https://nas:5001/photo',
'memories.testConnection': 'Проверить подключение',
'memories.testShort': 'Проверить',
'memories.testFirst': 'Сначала проверьте подключение',
@@ -71,10 +68,8 @@ const memories: TranslationStrings = {
'memories.error.addPhotos': 'Не удалось добавить фотографии',
'memories.error.removePhoto': 'Не удалось удалить фотографию',
'memories.error.toggleSharing': 'Не удалось обновить настройки доступа',
'memories.saveRouteNotConfigured':
'Маршрут сохранения не настроен для этого провайдера',
'memories.testRouteNotConfigured':
'Маршрут тестирования не настроен для этого провайдера',
'memories.saveRouteNotConfigured': 'Маршрут сохранения не настроен для этого провайдера',
'memories.testRouteNotConfigured': 'Маршрут тестирования не настроен для этого провайдера',
'memories.fillRequiredFields': 'Пожалуйста, заполните все обязательные поля',
};
export default memories;
+1 -2
View File
@@ -35,7 +35,6 @@ const notif: TranslationStrings = {
'notif.generic.title': 'Уведомление',
'notif.generic.text': 'У вас новое уведомление',
'notif.dev.unknown_event.title': '[DEV] Неизвестное событие',
'notif.dev.unknown_event.text':
'Тип события "{event}" не зарегистрирован в EVENT_NOTIFICATION_CONFIG',
'notif.dev.unknown_event.text': 'Тип события "{event}" не зарегистрирован в EVENT_NOTIFICATION_CONFIG',
};
export default notif;
+1 -2
View File
@@ -26,8 +26,7 @@ const notifications: TranslationStrings = {
'notifications.test.navigateText': 'Тестовое уведомление с переходом.',
'notifications.test.goThere': 'Перейти',
'notifications.test.adminTitle': 'Рассылка администратора',
'notifications.test.adminText':
'{actor} отправил тестовое уведомление всем администраторам.',
'notifications.test.adminText': '{actor} отправил тестовое уведомление всем администраторам.',
'notifications.test.tripTitle': '{actor} написал в вашей поездке',
'notifications.test.tripText': 'Тестовое уведомление для поездки "{trip}".',
'notifications.versionAvailable.title': 'Доступно обновление',
+31 -62
View File
@@ -15,98 +15,69 @@ const oauth: TranslationStrings = {
'oauth.scope.group.weather': 'Погода',
'oauth.scope.group.journey': 'Путешествия',
'oauth.scope.trips:read.label': 'Просмотр поездок и маршрутов',
'oauth.scope.trips:read.description':
'Чтение поездок, дней, заметок и участников',
'oauth.scope.trips:read.description': 'Чтение поездок, дней, заметок и участников',
'oauth.scope.trips:write.label': 'Редактирование поездок и маршрутов',
'oauth.scope.trips:write.description':
'Создание и обновление поездок, дней, заметок и управление участниками',
'oauth.scope.trips:write.description': 'Создание и обновление поездок, дней, заметок и управление участниками',
'oauth.scope.trips:delete.label': 'Удаление поездок',
'oauth.scope.trips:delete.description':
'Безвозвратное удаление поездок — это действие необратимо',
'oauth.scope.trips:delete.description': 'Безвозвратное удаление поездок — это действие необратимо',
'oauth.scope.trips:share.label': 'Управление ссылками на совместный доступ',
'oauth.scope.trips:share.description':
'Создание, обновление и отзыв публичных ссылок на поездки',
'oauth.scope.trips:share.description': 'Создание, обновление и отзыв публичных ссылок на поездки',
'oauth.scope.places:read.label': 'Просмотр мест и данных карты',
'oauth.scope.places:read.description':
'Чтение мест, назначений по дням, тегов и категорий',
'oauth.scope.places:read.description': 'Чтение мест, назначений по дням, тегов и категорий',
'oauth.scope.places:write.label': 'Управление местами',
'oauth.scope.places:write.description':
'Создание, обновление и удаление мест, назначений и тегов',
'oauth.scope.places:write.description': 'Создание, обновление и удаление мест, назначений и тегов',
'oauth.scope.atlas:read.label': 'Просмотр Atlas',
'oauth.scope.atlas:read.description':
'Чтение посещённых стран, регионов и списка желаний',
'oauth.scope.atlas:read.description': 'Чтение посещённых стран, регионов и списка желаний',
'oauth.scope.atlas:write.label': 'Управление Atlas',
'oauth.scope.atlas:write.description':
'Отмечать посещённые страны и регионы, управлять списком желаний',
'oauth.scope.atlas:write.description': 'Отмечать посещённые страны и регионы, управлять списком желаний',
'oauth.scope.packing:read.label': 'Просмотр списков вещей',
'oauth.scope.packing:read.description':
'Чтение вещей, сумок и назначений категорий',
'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:read.description': 'Чтение задач поездки и назначений категорий',
'oauth.scope.todos:write.label': 'Управление списками задач',
'oauth.scope.todos:write.description':
'Создание, обновление, отметка, удаление и переупорядочивание задач',
'oauth.scope.todos:write.description': 'Создание, обновление, отметка, удаление и переупорядочивание задач',
'oauth.scope.budget:read.label': 'Просмотр бюджета',
'oauth.scope.budget:read.description':
'Чтение статей бюджета и разбивки расходов',
'oauth.scope.budget:read.description': 'Чтение статей бюджета и разбивки расходов',
'oauth.scope.budget:write.label': 'Управление бюджетом',
'oauth.scope.budget:write.description':
'Создание, обновление и удаление статей бюджета',
'oauth.scope.budget:write.description': 'Создание, обновление и удаление статей бюджета',
'oauth.scope.reservations:read.label': 'Просмотр бронирований',
'oauth.scope.reservations:read.description':
'Чтение бронирований и сведений о проживании',
'oauth.scope.reservations:read.description': 'Чтение бронирований и сведений о проживании',
'oauth.scope.reservations:write.label': 'Управление бронированиями',
'oauth.scope.reservations:write.description':
'Создание, обновление, удаление и переупорядочивание бронирований',
'oauth.scope.reservations:write.description': 'Создание, обновление, удаление и переупорядочивание бронирований',
'oauth.scope.collab:read.label': 'Просмотр совместной работы',
'oauth.scope.collab:read.description':
'Чтение совместных заметок, опросов и сообщений',
'oauth.scope.collab:read.description': 'Чтение совместных заметок, опросов и сообщений',
'oauth.scope.collab:write.label': 'Управление совместной работой',
'oauth.scope.collab:write.description':
'Создание, обновление и удаление заметок, опросов и сообщений',
'oauth.scope.collab:write.description': 'Создание, обновление и удаление заметок, опросов и сообщений',
'oauth.scope.notifications:read.label': 'Просмотр уведомлений',
'oauth.scope.notifications:read.description':
'Чтение уведомлений в приложении и количества непрочитанных',
'oauth.scope.notifications:read.description': 'Чтение уведомлений в приложении и количества непрочитанных',
'oauth.scope.notifications:write.label': 'Управление уведомлениями',
'oauth.scope.notifications:write.description':
'Отмечать уведомления как прочитанные и отвечать на них',
'oauth.scope.notifications:write.description': 'Отмечать уведомления как прочитанные и отвечать на них',
'oauth.scope.vacay:read.label': 'Просмотр планов отпуска',
'oauth.scope.vacay:read.description':
'Чтение данных планирования отпуска, записей и статистики',
'oauth.scope.vacay:read.description': 'Чтение данных планирования отпуска, записей и статистики',
'oauth.scope.vacay:write.label': 'Управление планами отпуска',
'oauth.scope.vacay:write.description':
'Создание и управление записями отпуска, праздниками и командными планами',
'oauth.scope.vacay:write.description': 'Создание и управление записями отпуска, праздниками и командными планами',
'oauth.scope.geo:read.label': 'Карты и геокодирование',
'oauth.scope.geo:read.description':
'Поиск мест, разрешение URL карт и обратное геокодирование координат',
'oauth.scope.geo:read.description': 'Поиск мест, разрешение URL карт и обратное геокодирование координат',
'oauth.scope.weather:read.label': 'Прогнозы погоды',
'oauth.scope.weather:read.description':
'Получение прогнозов погоды для мест и дат поездки',
'oauth.scope.weather:read.description': 'Получение прогнозов погоды для мест и дат поездки',
'oauth.scope.journey:read.label': 'Просмотр путешествий',
'oauth.scope.journey:read.description':
'Чтение путешествий, записей и списка участников',
'oauth.scope.journey:read.description': 'Чтение путешествий, записей и списка участников',
'oauth.scope.journey:write.label': 'Управление путешествиями',
'oauth.scope.journey:write.description':
'Создание, обновление и удаление путешествий и их записей',
'oauth.scope.journey:write.description': 'Создание, обновление и удаление путешествий и их записей',
'oauth.scope.journey:share.label': 'Управление ссылками на путешествия',
'oauth.scope.journey:share.description':
'Создание, обновление и отзыв публичных ссылок для путешествий',
'oauth.scope.journey:share.description': 'Создание, обновление и отзыв публичных ссылок для путешествий',
'oauth.authorize.authorizing': 'Authorizing…', // en-fallback
'oauth.authorize.loading': 'Loading…', // en-fallback
'oauth.authorize.errorTitle': 'Authorization Error', // en-fallback
'oauth.authorize.loginTitle': 'Sign in to continue', // en-fallback
'oauth.authorize.loginDescription':
'{client} wants access to your TREK account. Please sign in first.', // en-fallback
'oauth.authorize.loginDescription': '{client} wants access to your TREK account. Please sign in first.', // en-fallback
'oauth.authorize.loginButton': 'Sign in to TREK', // en-fallback
'oauth.authorize.requestLabel': 'Authorization Request', // en-fallback
'oauth.authorize.requestDescription':
'This application is requesting access to your TREK account.', // en-fallback
'oauth.authorize.trustNote':
'Only grant access to applications you trust. Your data stays on your server.', // en-fallback
'oauth.authorize.requestDescription': 'This application is requesting access to your TREK account.', // en-fallback
'oauth.authorize.trustNote': 'Only grant access to applications you trust. Your data stays on your server.', // en-fallback
'oauth.authorize.selectScope': 'Select at least one scope', // en-fallback
'oauth.authorize.approveOneScope': 'Approve ({count} scope)', // en-fallback
'oauth.authorize.approveManyScopes': 'Approve ({count} scopes)', // en-fallback
@@ -115,9 +86,7 @@ const oauth: TranslationStrings = {
'oauth.authorize.choosePermissions': 'Choose which permissions to grant', // en-fallback
'oauth.authorize.permissionsRequested': 'Permissions requested', // en-fallback
'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback
'oauth.authorize.alwaysTool.listTrips':
'List your trips so the AI can discover trip IDs', // en-fallback
'oauth.authorize.alwaysTool.getTripSummary':
'Read a trip overview needed to use any other tool', // en-fallback
'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback
'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback
};
export default oauth;
+3 -6
View File
@@ -7,8 +7,7 @@ const packing: TranslationStrings = {
'packing.importTitle': 'Импорт списка вещей',
'packing.importHint':
'Один предмет на строку. Категория и количество — через запятую, точку с запятой или табуляцию: Название, Категория, Количество',
'packing.importPlaceholder':
'Зубная щётка\nСолнцезащитный крем, Гигиена\nФутболки, Одежда, 5\nПаспорт, Документы',
'packing.importPlaceholder': 'Зубная щётка\nСолнцезащитный крем, Гигиена\nФутболки, Одежда, 5\nПаспорт, Документы',
'packing.importCsv': 'Загрузить CSV/TXT',
'packing.importAction': 'Импортировать {count}',
'packing.importSuccess': '{count} предметов импортировано',
@@ -51,10 +50,8 @@ const packing: TranslationStrings = {
'packing.bagName': 'Название...',
'packing.addBag': 'Добавить багаж',
'packing.changeCategory': 'Изменить категорию',
'packing.confirm.clearChecked':
'Вы уверены, что хотите удалить {count} отмеченных вещей?',
'packing.confirm.deleteCat':
'Вы уверены, что хотите удалить категорию «{name}» с {count} вещами?',
'packing.confirm.clearChecked': 'Вы уверены, что хотите удалить {count} отмеченных вещей?',
'packing.confirm.deleteCat': 'Вы уверены, что хотите удалить категорию «{name}» с {count} вещами?',
'packing.defaultCategory': 'Другое',
'packing.toast.saveError': 'Ошибка сохранения',
'packing.toast.deleteError': 'Ошибка удаления',
+12 -24
View File
@@ -32,32 +32,20 @@ const perm: TranslationStrings = {
'perm.action.collab_edit': 'Совместная работа (заметки, опросы, чат)',
'perm.action.share_manage': 'Управлять ссылками для обмена',
'perm.actionHint.trip_create': 'Кто может создавать новые поездки',
'perm.actionHint.trip_edit':
'Кто может менять название, даты, описание и валюту поездки',
'perm.actionHint.trip_edit': 'Кто может менять название, даты, описание и валюту поездки',
'perm.actionHint.trip_delete': 'Кто может безвозвратно удалить поездку',
'perm.actionHint.trip_archive':
'Кто может архивировать или разархивировать поездку',
'perm.actionHint.trip_archive': 'Кто может архивировать или разархивировать поездку',
'perm.actionHint.trip_cover_upload': 'Кто может загружать или менять обложку',
'perm.actionHint.member_manage':
'Кто может приглашать или удалять участников поездки',
'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':
'Кто может создавать или удалять публичные ссылки для обмена',
'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': 'Кто может создавать или удалять публичные ссылки для обмена',
};
export default perm;
+7 -14
View File
@@ -6,13 +6,10 @@ const places: TranslationStrings = {
'places.sidebarDrop': 'Отпустите для импорта',
'places.importFileHint':
'Импортируйте файлы .gpx, .kml или .kmz из инструментов, таких как Google My Maps, Google Earth или GPS-трекер.',
'places.importFileDropHere':
'Нажмите для выбора файла или перетащите его сюда',
'places.importFileDropHere': 'Нажмите для выбора файла или перетащите его сюда',
'places.importFileDropActive': 'Отпустите файл для выбора',
'places.importFileUnsupported':
'Неподдерживаемый тип файла. Используйте .gpx, .kml или .kmz.',
'places.importFileTooLarge':
'Файл слишком большой. Максимальный размер загрузки — {maxMb} MB.',
'places.importFileUnsupported': 'Неподдерживаемый тип файла. Используйте .gpx, .kml или .kmz.',
'places.importFileTooLarge': 'Файл слишком большой. Максимальный размер загрузки — {maxMb} MB.',
'places.importFileError': 'Ошибка импорта',
'places.importAllSkipped': 'Все места уже были в поездке.',
'places.gpxImported': '{count} мест импортировано из GPX',
@@ -30,16 +27,13 @@ const places: TranslationStrings = {
'places.kmlKmzImported': '{count} мест импортировано из KMZ/KML',
'places.urlResolved': 'Место импортировано из URL',
'places.importList': 'Импорт списка',
'places.kmlKmzSummaryValues':
'Placemarks: {total} • Импортировано: {created} • Пропущено: {skipped}',
'places.kmlKmzSummaryValues': 'Placemarks: {total} • Импортировано: {created} • Пропущено: {skipped}',
'places.importGoogleList': 'Список Google',
'places.importNaverList': 'Список Naver',
'places.googleListHint':
'Вставьте ссылку на общий список Google Maps для импорта всех мест.',
'places.googleListHint': 'Вставьте ссылку на общий список Google Maps для импорта всех мест.',
'places.googleListImported': '{count} мест импортировано из "{list}"',
'places.googleListError': 'Не удалось импортировать список Google Maps',
'places.naverListHint':
'Вставьте ссылку на общий список Naver Maps для импорта всех мест.',
'places.naverListHint': 'Вставьте ссылку на общий список Naver Maps для импорта всех мест.',
'places.naverListImported': '{count} мест импортировано из "{list}"',
'places.naverListError': 'Не удалось импортировать список Naver Maps',
'places.viewDetails': 'Подробности',
@@ -76,8 +70,7 @@ const places: TranslationStrings = {
'places.formNotes': 'Заметки',
'places.formNotesPlaceholder': 'Личные заметки...',
'places.formReservation': 'Бронирование',
'places.reservationNotesPlaceholder':
'Заметки о бронировании, номер подтверждения...',
'places.reservationNotesPlaceholder': 'Заметки о бронировании, номер подтверждения...',
'places.mapsSearchPlaceholder': 'Поиск мест...',
'places.mapsSearchError': 'Ошибка поиска мест.',
'places.loadingDetails': 'Загрузка данных о месте…',
+2 -4
View File
@@ -33,8 +33,7 @@ const planner: TranslationStrings = {
'planner.resConfirmed': 'Бронирование подтверждено · ',
'planner.notePlaceholder': 'Заметка…',
'planner.noteTimePlaceholder': 'Время (необязательно)',
'planner.noteExamplePlaceholder':
'напр. S3 в 14:30 с вокзала, паром с причала 7, обеденный перерыв…',
'planner.noteExamplePlaceholder': 'напр. S3 в 14:30 с вокзала, паром с причала 7, обеденный перерыв…',
'planner.totalCost': 'Общая стоимость',
'planner.searchPlaces': 'Поиск мест…',
'planner.allCategories': 'Все категории',
@@ -48,8 +47,7 @@ const planner: TranslationStrings = {
'planner.route': 'Маршрут',
'planner.optimize': 'Оптимизировать',
'planner.openGoogleMaps': 'Открыть в Google Maps',
'planner.selectDayHint':
'Выберите день из списка слева для просмотра плана дня',
'planner.selectDayHint': 'Выберите день из списка слева для просмотра плана дня',
'planner.noPlacesForDay': 'На этот день мест пока нет',
'planner.addPlacesLink': 'Добавить места →',
'planner.minTotal': 'мин. всего',
+19 -38
View File
@@ -3,12 +3,10 @@ import type { TranslationStrings } from '../types';
const reservations: TranslationStrings = {
'reservations.title': 'Бронирования',
'reservations.empty': 'Пока нет бронирований',
'reservations.emptyHint':
'Добавьте бронирования на авиабилеты, отели и другое',
'reservations.emptyHint': 'Добавьте бронирования на авиабилеты, отели и другое',
'reservations.add': 'Добавить бронирование',
'reservations.addManual': 'Ручное бронирование',
'reservations.placeHint':
'Совет: бронирования лучше создавать прямо из места, чтобы связать их с планом дня.',
'reservations.placeHint': 'Совет: бронирования лучше создавать прямо из места, чтобы связать их с планом дня.',
'reservations.confirmed': 'Подтверждено',
'reservations.pending': 'Ожидание',
'reservations.summary': '{confirmed} подтв., {pending} ожид.',
@@ -34,8 +32,7 @@ const reservations: TranslationStrings = {
'reservations.layover.connection': 'Стыковка',
'reservations.layover.layover': 'Пересадка',
'reservations.needsReview': 'Проверить',
'reservations.needsReviewHint':
'Аэропорт не удалось определить автоматически — подтвердите местоположение.',
'reservations.needsReviewHint': 'Аэропорт не удалось определить автоматически — подтвердите местоположение.',
'reservations.searchLocation': 'Искать станцию, порт, адрес...',
'reservations.meta.trainNumber': 'Номер поезда',
'reservations.meta.platform': 'Платформа',
@@ -65,8 +62,7 @@ const reservations: TranslationStrings = {
'reservations.type.bicycle': 'Велосипед',
'reservations.type.taxi': 'Такси',
'reservations.type.transport_other': 'Другое',
'reservations.confirm.delete':
'Вы уверены, что хотите удалить бронирование «{name}»?',
'reservations.confirm.delete': 'Вы уверены, что хотите удалить бронирование «{name}»?',
'reservations.confirm.deleteTitle': 'Удалить бронирование?',
'reservations.confirm.deleteBody': '«{name}» будет удалено навсегда.',
'reservations.toast.updated': 'Бронирование обновлено',
@@ -100,8 +96,7 @@ const reservations: TranslationStrings = {
'reservations.budgetCategory': 'Категория бюджета',
'reservations.budgetCategoryPlaceholder': 'напр. Транспорт, Проживание',
'reservations.budgetCategoryAuto': 'Авто (по типу бронирования)',
'reservations.budgetHint':
'При сохранении будет автоматически создана запись бюджета.',
'reservations.budgetHint': 'При сохранении будет автоматически создана запись бюджета.',
'reservations.departureDate': 'Вылет',
'reservations.arrivalDate': 'Прилёт',
'reservations.departureTime': 'Время вылета',
@@ -122,60 +117,46 @@ const reservations: TranslationStrings = {
'reservations.span.start': 'Начало',
'reservations.span.end': 'Конец',
'reservations.span.ongoing': 'Продолжается',
'reservations.validation.endBeforeStart':
'Дата/время окончания должны быть позже даты/времени начала',
'reservations.validation.endBeforeStart': 'Дата/время окончания должны быть позже даты/времени начала',
'reservations.addBooking': 'Добавить бронирование',
'reservations.import.title': 'Импорт подтверждений бронирования',
'reservations.import.cta': 'Импортировать из файла',
'reservations.import.dropHere':
'Перетащите файлы подтверждений бронирования сюда или нажмите для выбора',
'reservations.import.dropHere': 'Перетащите файлы подтверждений бронирования сюда или нажмите для выбора',
'reservations.import.dropActive': 'Отпустите файлы для импорта',
'reservations.import.acceptedFormats':
'Принимаются: EML, PDF, PKPass, HTML, TXT (макс. 10 МБ каждый, до 5 файлов)',
'reservations.import.acceptedFormats': 'Принимаются: EML, PDF, PKPass, HTML, TXT (макс. 10 МБ каждый, до 5 файлов)',
'reservations.import.parsing': 'Обработка файлов…',
'reservations.import.previewHeading': 'Найдено {count} бронирование(й)',
'reservations.import.previewEmpty':
'Из загруженных файлов не удалось извлечь бронирования.',
'reservations.import.previewEmpty': 'Из загруженных файлов не удалось извлечь бронирования.',
'reservations.import.removeItem': 'Удалить',
'reservations.import.confirm': 'Импортировать {count} бронирование(й)',
'reservations.import.back': 'Назад',
'reservations.import.success': '{count} бронирование(й) импортировано',
'reservations.import.partialFailure':
'{created} импортировано, {failed} не удалось',
'reservations.import.partialFailure': '{created} импортировано, {failed} не удалось',
'reservations.import.error':
'Обработка не удалась. Убедитесь, что файл является действительным подтверждением бронирования.',
'reservations.import.unavailable':
'Импорт бронирований недоступен на этом сервере.',
'reservations.import.unsupportedFormat':
'Неподдерживаемый формат файла. Используйте EML, PDF, PKPass, HTML или TXT.',
'reservations.import.fileTooLarge':
'Файл «{name}» превышает ограничение в 10 МБ.',
'reservations.import.unavailable': 'Импорт бронирований недоступен на этом сервере.',
'reservations.import.unsupportedFormat': 'Неподдерживаемый формат файла. Используйте EML, PDF, PKPass, HTML или TXT.',
'reservations.import.fileTooLarge': 'Файл «{name}» превышает ограничение в 10 МБ.',
'reservations.airtrail.title': 'Импорт из AirTrail',
'reservations.airtrail.cta': 'AirTrail',
'reservations.airtrail.synced': 'AirTrail',
'reservations.airtrail.syncedHint':
'Синхронизировано с AirTrail — изменения синхронизируются в обе стороны.',
'reservations.airtrail.syncedHint': 'Синхронизировано с AirTrail — изменения синхронизируются в обе стороны.',
'reservations.airtrail.notSynced': 'Не синхронизировано',
'reservations.airtrail.notSyncedHint':
'Этот рейс был удалён в AirTrail и больше не синхронизируется.',
'reservations.airtrail.loadError':
'Не удалось загрузить ваши рейсы из AirTrail.',
'reservations.airtrail.notSyncedHint': 'Этот рейс был удалён в AirTrail и больше не синхронизируется.',
'reservations.airtrail.loadError': 'Не удалось загрузить ваши рейсы из AirTrail.',
'reservations.airtrail.imported': 'Импортировано рейсов: {count}',
'reservations.airtrail.skippedDuplicate':
'{count} уже в этой поездке, пропущено',
'reservations.airtrail.skippedDuplicate': '{count} уже в этой поездке, пропущено',
'reservations.airtrail.nothingImported': 'Нечего импортировать.',
'reservations.airtrail.importError': 'Импорт не удался. Повторите попытку.',
'reservations.airtrail.undo': 'Импорт из AirTrail',
'reservations.airtrail.alreadyImported': 'Импортировано',
'reservations.airtrail.duringTrip': 'Во время этой поездки',
'reservations.airtrail.otherFlights': 'Другие рейсы',
'reservations.airtrail.empty':
'В вашей учётной записи AirTrail не найдено рейсов.',
'reservations.airtrail.empty': 'В вашей учётной записи AirTrail не найдено рейсов.',
'reservations.airtrail.importCta': 'Импортировать {count}',
'reservations.costsLabel': 'Costs',
'reservations.createExpense': 'Create expense',
'reservations.createExpenseHint':
'Saves the booking, then opens the Costs editor.',
'reservations.createExpenseHint': 'Saves the booking, then opens the Costs editor.',
'reservations.linkedExpense': 'Linked expense',
'reservations.removeExpense': 'Remove expense',
};
+32 -50
View File
@@ -14,12 +14,10 @@ const settings: TranslationStrings = {
'settings.mapTemplate': 'Шаблон карты',
'settings.mapTemplatePlaceholder.select': 'Выберите шаблон...',
'settings.mapDefaultHint': 'Оставьте пустым для OpenStreetMap (по умолчанию)',
'settings.mapTemplatePlaceholder':
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
'settings.mapTemplatePlaceholder': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
'settings.mapHint': 'URL-шаблон для тайлов карты',
'settings.mapProvider': 'Провайдер карты',
'settings.mapProviderHint':
'Применяется к Trip Planner и Journey. Atlas всегда использует Leaflet.',
'settings.mapProviderHint': 'Применяется к Trip Planner и Journey. Atlas всегда использует Leaflet.',
'settings.mapLeafletSubtitle': 'Классические 2D, любые растровые тайлы',
'settings.mapMapboxSubtitle': 'Векторные тайлы, 3D-здания и рельеф',
'settings.mapExperimental': 'Экспериментально',
@@ -30,13 +28,10 @@ const settings: TranslationStrings = {
'settings.mapStylePlaceholder': 'Выберите стиль Mapbox',
'settings.mapStyleHint': 'Preset или собственный URL mapbox://styles/USER/ID',
'settings.map3dBuildings': '3D-здания и рельеф',
'settings.map3dHint':
'Наклон + настоящие 3D-здания — работает со всеми стилями, включая спутник.',
'settings.map3dHint': 'Наклон + настоящие 3D-здания — работает со всеми стилями, включая спутник.',
'settings.mapHighQuality': 'Режим высокого качества',
'settings.mapHighQualityHint':
'Сглаживание + проекция глобуса для более чётких краёв и реалистичного вида мира.',
'settings.mapHighQualityWarning':
'Может повлиять на производительность на слабых устройствах.',
'settings.mapHighQualityHint': 'Сглаживание + проекция глобуса для более чётких краёв и реалистичного вида мира.',
'settings.mapHighQualityWarning': 'Может повлиять на производительность на слабых устройствах.',
'settings.mapTipLabel': 'Совет:',
'settings.mapTip':
'Зажмите правую кнопку мыши и перетащите, чтобы повернуть/наклонить карту. Клик средней кнопкой — добавить место (правая кнопка зарезервирована для вращения).',
@@ -45,11 +40,9 @@ const settings: TranslationStrings = {
'settings.saveMap': 'Сохранить карту',
'settings.apiKeys': 'API-ключи',
'settings.mapsKey': 'API-ключ Google Maps',
'settings.mapsKeyHint':
'Для поиска мест. Требуется Places API (New). Получите на console.cloud.google.com',
'settings.mapsKeyHint': 'Для поиска мест. Требуется Places API (New). Получите на console.cloud.google.com',
'settings.weatherKey': 'API-ключ OpenWeatherMap',
'settings.weatherKeyHint':
'Для данных о погоде. Бесплатно на openweathermap.org/api',
'settings.weatherKeyHint': 'Для данных о погоде. Бесплатно на openweathermap.org/api',
'settings.keyPlaceholder': 'Введите ключ...',
'settings.configured': 'Настроено',
'settings.saveKeys': 'Сохранить ключи',
@@ -78,8 +71,7 @@ const settings: TranslationStrings = {
'settings.notificationsDisabled':
'Уведомления не настроены. Попросите администратора включить уведомления по электронной почте или webhook.',
'settings.notificationsActive': 'Активный канал',
'settings.notificationsManagedByAdmin':
'События уведомлений настраиваются администратором.',
'settings.notificationsManagedByAdmin': 'События уведомлений настраиваются администратором.',
'settings.on': 'Вкл.',
'settings.off': 'Выкл.',
'settings.mcp.title': 'Настройка MCP',
@@ -93,8 +85,7 @@ const settings: TranslationStrings = {
'settings.mcp.copied': 'Скопировано!',
'settings.mcp.apiTokens': 'API-токены',
'settings.mcp.createToken': 'Создать токен',
'settings.mcp.noTokens':
'Токенов пока нет. Создайте один для подключения MCP-клиентов.',
'settings.mcp.noTokens': 'Токенов пока нет. Создайте один для подключения MCP-клиентов.',
'settings.mcp.tokenCreatedAt': 'Создан',
'settings.mcp.tokenUsedAt': 'Использован',
'settings.mcp.deleteTokenTitle': 'Удалить токен',
@@ -102,8 +93,7 @@ const settings: TranslationStrings = {
'Этот токен перестанет работать немедленно. Любой MCP-клиент, использующий его, потеряет доступ.',
'settings.mcp.modal.createTitle': 'Создать API-токен',
'settings.mcp.modal.tokenName': 'Название токена',
'settings.mcp.modal.tokenNamePlaceholder':
'напр. Claude Desktop, Рабочий ноутбук',
'settings.mcp.modal.tokenNamePlaceholder': 'напр. Claude Desktop, Рабочий ноутбук',
'settings.mcp.modal.creating': 'Создание…',
'settings.mcp.modal.create': 'Создать токен',
'settings.mcp.modal.createdTitle': 'Токен создан',
@@ -139,16 +129,13 @@ const settings: TranslationStrings = {
'settings.oauth.sessionExpires': 'Истекает',
'settings.oauth.revoke': 'Отозвать',
'settings.oauth.revokeSession': 'Отозвать сессию',
'settings.oauth.revokeSessionMessage':
'Это немедленно отзовёт доступ для данной сессии OAuth.',
'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.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.redirectUrisPlaceholder': 'https://your-app.com/callback\nhttps://your-app.com/auth',
'settings.oauth.modal.redirectUrisHint':
'Один URI на строку. Требуется HTTPS (localhost исключён). Требуется точное совпадение.',
'settings.oauth.modal.scopes': 'Разрешённые области доступа',
@@ -161,15 +148,13 @@ const settings: TranslationStrings = {
'settings.oauth.modal.createdTitle': 'Клиент зарегистрирован',
'settings.oauth.modal.createdWarning':
'Секрет клиента отображается только один раз. Скопируйте его сейчас — его нельзя будет восстановить.',
'settings.oauth.toast.createError':
'Не удалось зарегистрировать клиент OAuth',
'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.oauth.modal.machineClient':
'Машинный клиент (без входа через браузер)',
'settings.oauth.modal.machineClient': 'Машинный клиент (без входа через браузер)',
'settings.oauth.modal.machineClientHint':
'Использует грант client_credentials — URI перенаправления не требуются. Токен выдаётся напрямую через client_id + client_secret и действует от вашего имени в пределах выбранных областей.',
'settings.oauth.modal.machineClientUsage':
@@ -190,8 +175,7 @@ const settings: TranslationStrings = {
'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.businessClassDreamer': 'Business Class Dreamer',
'settings.about.supporter.tier.budgetTraveller': 'Budget Traveller',
'settings.about.supporter.tier.hostelBunkmate': 'Hostel Bunkmate',
'settings.about.description':
@@ -214,8 +198,7 @@ const settings: TranslationStrings = {
'settings.passwordRequired': 'Введите текущий и новый пароль',
'settings.passwordTooShort': 'Пароль должен содержать не менее 8 символов',
'settings.passwordMismatch': 'Пароли не совпадают',
'settings.passwordWeak':
'Пароль должен содержать заглавные, строчные буквы, цифру и специальный символ',
'settings.passwordWeak': 'Пароль должен содержать заглавные, строчные буквы, цифру и специальный символ',
'settings.passwordChanged': 'Пароль успешно изменён',
'settings.deleteAccount': 'Удалить аккаунт',
'settings.deleteAccountTitle': 'Удалить ваш аккаунт?',
@@ -235,8 +218,7 @@ const settings: TranslationStrings = {
'settings.mfa.backupTitle': 'Резервные коды',
'settings.mfa.backupDescription':
'Используйте эти одноразовые коды, если потеряете доступ к приложению-аутентификатору.',
'settings.mfa.backupWarning':
'Сохраните их сейчас. Каждый код можно использовать только один раз.',
'settings.mfa.backupWarning': 'Сохраните их сейчас. Каждый код можно использовать только один раз.',
'settings.mfa.backupCopy': 'Скопировать коды',
'settings.mfa.backupDownload': 'Скачать TXT',
'settings.mfa.backupPrint': 'Печать / PDF',
@@ -244,15 +226,13 @@ const settings: TranslationStrings = {
'settings.mfa.enabled': '2FA включена для вашего аккаунта.',
'settings.mfa.disabled': '2FA не включена.',
'settings.mfa.setup': 'Настроить аутентификатор',
'settings.mfa.scanQr':
'Отсканируйте QR-код приложением или введите ключ вручную.',
'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.disableHint': 'Введите пароль аккаунта и текущий код из аутентификатора.',
'settings.mfa.disable': 'Отключить 2FA',
'settings.mfa.toastEnabled': 'Двухфакторная аутентификация включена',
'settings.mfa.toastDisabled': 'Двухфакторная аутентификация отключена',
@@ -290,16 +270,15 @@ const settings: TranslationStrings = {
'settings.ntfyUrl.tokenHint': 'Требуется для тем, защищённых паролем.',
'settings.ntfyUrl.saved': 'Настройки Ntfy сохранены',
'settings.ntfyUrl.test': 'Тест',
'settings.ntfyUrl.testSuccess':
'Тестовое уведомление Ntfy успешно отправлено',
'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',
"settings.currency": "Currency",
"settings.currencyHint": "All amounts in Costs are converted to and shown in this currency.",
'settings.currency': 'Currency',
'settings.currencyHint': 'All amounts in Costs are converted to and shown in this currency.',
'settings.passkey.title': 'Passkeys',
'settings.passkey.description':
'Входите быстрее и с защитой от фишинга с помощью passkey — отпечатка пальца, лица, PIN-кода или аппаратного ключа. Ваш пароль остаётся как резервный способ.',
@@ -307,8 +286,7 @@ const settings: TranslationStrings = {
'Passkeys включены, но ещё не полностью настроены на этом сервере. Попросите администратора задать домен WebAuthn.',
'settings.passkey.add': 'Добавить passkey',
'settings.passkey.addTitle': 'Добавить passkey',
'settings.passkey.passwordPrompt':
'Подтвердите текущий пароль, затем следуйте подсказке на устройстве.',
'settings.passkey.passwordPrompt': 'Подтвердите текущий пароль, затем следуйте подсказке на устройстве.',
'settings.passkey.passwordRequired': 'Требуется ваш текущий пароль.',
'settings.passkey.namePlaceholder': 'Название (необязательно, напр. "iPhone")',
'settings.passkey.addedToast': 'Passkey добавлен',
@@ -324,17 +302,21 @@ const settings: TranslationStrings = {
'settings.passkey.lastUsed': 'Последнее использование',
'settings.passkey.neverUsed': 'Не использовался',
'settings.mapPoiPill': 'Поиск мест на карте',
'settings.mapPoiPillHint': 'Показывать на карте поездки кнопку категорий, чтобы находить рядом рестораны, отели и другие места из OpenStreetMap.',
'settings.mapPoiPillHint':
'Показывать на карте поездки кнопку категорий, чтобы находить рядом рестораны, отели и другие места из OpenStreetMap.',
'settings.airtrail.title': 'AirTrail',
'settings.airtrail.hint': 'Подключите свой self-hosted AirTrail для импорта и синхронизации рейсов. Создайте ключ API в AirTrail в разделе «Настройки → Безопасность».',
'settings.airtrail.hint':
'Подключите свой self-hosted AirTrail для импорта и синхронизации рейсов. Создайте ключ API в AirTrail в разделе «Настройки → Безопасность».',
'settings.airtrail.url': 'URL экземпляра',
'settings.airtrail.apiKey': 'Ключ API',
'settings.airtrail.apiKeyPlaceholder': 'Bearer-ключ API',
'settings.airtrail.apiKeyHint': 'Создаётся в AirTrail в разделе «Настройки → Безопасность». Хранится в зашифрованном виде.',
'settings.airtrail.apiKeyHint':
'Создаётся в AirTrail в разделе «Настройки → Безопасность». Хранится в зашифрованном виде.',
'settings.airtrail.allowInsecureTls': 'Разрешить самоподписанные сертификаты',
'settings.airtrail.allowInsecureTlsHint': 'Включайте только для доверенного экземпляра в вашей собственной сети.',
'settings.airtrail.writeBack': 'Записывать изменения обратно в AirTrail',
'settings.airtrail.writeBackHint': 'По умолчанию выключено: AirTrail является источником истины, а TREK только читает из него. Включите, чтобы отправлять изменения, сделанные в TREK, обратно в AirTrail.',
'settings.airtrail.writeBackHint':
'По умолчанию выключено: AirTrail является источником истины, а TREK только читает из него. Включите, чтобы отправлять изменения, сделанные в TREK, обратно в AirTrail.',
'settings.airtrail.connected': 'Подключено',
'settings.airtrail.notConnected': 'Не подключено',
'settings.airtrail.toast.saved': 'Подключение к AirTrail сохранено',
+9 -18
View File
@@ -5,11 +5,9 @@ const system_notice: TranslationStrings = {
'system_notice.welcome_v1.body':
'Ваш универсальный планировщик путешествий. Создавайте маршруты, делитесь поездками с друзьями и оставайтесь организованными — онлайн и офлайн.',
'system_notice.welcome_v1.cta_label': 'Спланировать поездку',
'system_notice.welcome_v1.hero_alt':
'Живописное место назначения с интерфейсом TREK',
'system_notice.welcome_v1.hero_alt': 'Живописное место назначения с интерфейсом TREK',
'system_notice.welcome_v1.highlight_plan': 'Маршруты по дням',
'system_notice.welcome_v1.highlight_share':
'Совместное планирование с партнёрами',
'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.',
@@ -25,34 +23,27 @@ const system_notice: TranslationStrings = {
'system_notice.v3_journey.body':
'Документируйте путешествия в виде рассказов с хронологиями, фотогалереями и интерактивными картами.',
'system_notice.v3_journey.cta_label': 'Открыть Journey',
'system_notice.v3_journey.highlight_timeline':
'Ежедневная хронология и галерея',
'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.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_search': 'Автодополнение поиска мест в реальном времени',
'system_notice.v3_features.highlight_import': 'Импорт мест из KMZ/KML-файлов',
'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_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_deprecated': 'Статические токены trek_ устарели',
'system_notice.v3_mcp.highlight_tools': 'Расширенный набор инструментов',
'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) всегда помогает держать свет включённым.',
'system_notice.v3014_whitespace_collision.title':
'Требуется действие: конфликт учётных записей',
'system_notice.v3014_whitespace_collision.title': 'Требуется действие: конфликт учётных записей',
'system_notice.v3014_whitespace_collision.body':
'Обновление 3.0.14 обнаружило один или несколько конфликтов имён пользователей или адресов электронной почты, вызванных ведущими или завершающими пробелами в сохранённых значениях. Затронутые учётные записи были автоматически переименованы. Проверьте логи сервера на строки, начинающиеся с **[migration] WHITESPACE COLLISION**, чтобы определить учётные записи, требующие проверки.',
};
+1 -1
View File
@@ -9,7 +9,7 @@ const trip: TranslationStrings = {
'trip.tabs.packingShort': 'Вещи',
'trip.tabs.lists': 'Списки',
'trip.tabs.listsShort': 'Списки',
'trip.tabs.budget': "Costs",
'trip.tabs.budget': 'Costs',
'trip.tabs.files': 'Файлы',
'trip.loading': 'Загрузка поездки...',
'trip.loadingPhotos': 'Загрузка фото мест...',
+1 -2
View File
@@ -11,7 +11,6 @@ const trips: TranslationStrings = {
'trips.reminderDays': 'дней',
'trips.reminderCustom': 'Другое',
'trips.reminderDaysBefore': 'дней до отъезда',
'trips.reminderDisabledHint':
'Напоминания о поездках отключены. Включите их в Админ > Настройки > Уведомления.',
'trips.reminderDisabledHint': 'Напоминания о поездках отключены. Включите их в Админ > Настройки > Уведомления.',
};
export default trips;
+14 -28
View File
@@ -8,8 +8,7 @@ const vacay: TranslationStrings = {
'vacay.addPrevYear': 'Добавить предыдущий год',
'vacay.removeYear': 'Удалить год',
'vacay.removeYearConfirm': 'Удалить {year}?',
'vacay.removeYearHint':
'Все записи об отпуске и корпоративные выходные за этот год будут безвозвратно удалены.',
'vacay.removeYearHint': 'Все записи об отпуске и корпоративные выходные за этот год будут безвозвратно удалены.',
'vacay.remove': 'Удалить',
'vacay.persons': 'Люди',
'vacay.noPersons': 'Никто не добавлен',
@@ -17,8 +16,7 @@ const vacay: TranslationStrings = {
'vacay.editPerson': 'Редактировать',
'vacay.removePerson': 'Удалить человека',
'vacay.removePersonConfirm': 'Удалить {name}?',
'vacay.removePersonHint':
'Все записи об отпуске этого человека будут безвозвратно удалены.',
'vacay.removePersonHint': 'Все записи об отпуске этого человека будут безвозвратно удалены.',
'vacay.personName': 'Имя',
'vacay.personNamePlaceholder': 'Введите имя',
'vacay.color': 'Цвет',
@@ -35,8 +33,7 @@ const vacay: TranslationStrings = {
'vacay.remaining': 'Осталось',
'vacay.carriedOver': 'из {year}',
'vacay.blockWeekends': 'Блокировать выходные',
'vacay.blockWeekendsHint':
'Запретить записи об отпуске в субботу и воскресенье',
'vacay.blockWeekendsHint': 'Запретить записи об отпуске в субботу и воскресенье',
'vacay.weekendDays': 'Выходные дни',
'vacay.mon': 'Пн',
'vacay.tue': 'Вт',
@@ -51,24 +48,19 @@ const vacay: TranslationStrings = {
'vacay.selectRegion': 'Выберите регион (необязательно)',
'vacay.companyHolidays': 'Корпоративные выходные',
'vacay.companyHolidaysHint': 'Разрешить отмечать корпоративные выходные дни',
'vacay.companyHolidaysNoDeduct':
'Корпоративные выходные не вычитаются из дней отпуска.',
'vacay.companyHolidaysNoDeduct': 'Корпоративные выходные не вычитаются из дней отпуска.',
'vacay.weekStart': 'Неделя начинается с',
'vacay.weekStartHint':
'Выберите, начинается ли неделя с понедельника или воскресенья',
'vacay.weekStartHint': 'Выберите, начинается ли неделя с понедельника или воскресенья',
'vacay.carryOver': 'Перенос',
'vacay.carryOverHint':
'Автоматически переносить оставшиеся дни отпуска на следующий год',
'vacay.carryOverHint': 'Автоматически переносить оставшиеся дни отпуска на следующий год',
'vacay.sharing': 'Общий доступ',
'vacay.sharingHint':
'Поделитесь планом отпуска с другими пользователями TREK',
'vacay.sharingHint': 'Поделитесь планом отпуска с другими пользователями TREK',
'vacay.owner': 'Владелец',
'vacay.shareEmailPlaceholder': 'Эл. почта пользователя TREK',
'vacay.shareSuccess': 'План успешно предоставлен',
'vacay.shareError': 'Не удалось поделиться планом',
'vacay.dissolve': 'Разделить объединение',
'vacay.dissolveHint':
'Снова разделить календари. Ваши записи будут сохранены.',
'vacay.dissolveHint': 'Снова разделить календари. Ваши записи будут сохранены.',
'vacay.dissolveAction': 'Разделить',
'vacay.dissolved': 'Календарь разделён',
'vacay.fusedWith': 'Объединён с',
@@ -76,8 +68,7 @@ const vacay: TranslationStrings = {
'vacay.noData': 'Нет данных',
'vacay.changeColor': 'Изменить цвет',
'vacay.inviteUser': 'Пригласить пользователя',
'vacay.inviteHint':
'Пригласите другого пользователя TREK для совместного календаря отпусков.',
'vacay.inviteHint': 'Пригласите другого пользователя TREK для совместного календаря отпусков.',
'vacay.selectUser': 'Выберите пользователя',
'vacay.sendInvite': 'Отправить приглашение',
'vacay.inviteSent': 'Приглашение отправлено',
@@ -89,16 +80,11 @@ const vacay: TranslationStrings = {
'vacay.acceptFusion': 'Принять и объединить',
'vacay.inviteTitle': 'Запрос на объединение',
'vacay.inviteWantsToFuse': 'хочет объединить календарь отпусков с вами.',
'vacay.fuseInfo1':
'Вы оба будете видеть все записи об отпуске в одном общем календаре.',
'vacay.fuseInfo2':
'Обе стороны могут создавать и редактировать записи друг для друга.',
'vacay.fuseInfo3':
'Обе стороны могут удалять записи и изменять право на отпуск.',
'vacay.fuseInfo4':
'Настройки, такие как праздники и корпоративные выходные, становятся общими.',
'vacay.fuseInfo5':
'Объединение можно отменить в любое время любой из сторон. Ваши записи будут сохранены.',
'vacay.fuseInfo1': 'Вы оба будете видеть все записи об отпуске в одном общем календаре.',
'vacay.fuseInfo2': 'Обе стороны могут создавать и редактировать записи друг для друга.',
'vacay.fuseInfo3': 'Обе стороны могут удалять записи и изменять право на отпуск.',
'vacay.fuseInfo4': 'Настройки, такие как праздники и корпоративные выходные, становятся общими.',
'vacay.fuseInfo5': 'Объединение можно отменить в любое время любой из сторон. Ваши записи будут сохранены.',
'vacay.addCalendar': 'Добавить календарь',
'vacay.calendarColor': 'Цвет',
'vacay.calendarLabel': 'Название',