* Add workspace MCP settings and token access controls. Ship MCP settings UI, OAuth revoke/list helpers, Passport deploy wiring, and workspace.token:mcp gating so assistants can connect without pulling in welcome/onboarding from the parent epic. Co-authored-by: Cursor <cursoragent@cursor.com> * Type MCP client config shapes instead of string checks. Encode http/config-root on each advanced client and tighten primary client ids so snippet generation does not branch on magic strings. Co-authored-by: Cursor <cursoragent@cursor.com> * Polish MCP settings follow-ups from review. Translate Ukrainian MCP copy, deep-link ChatGPT into connector creation, drop an unused asset and revoke arg, and assert PATs are rejected on the MCP endpoint. Co-authored-by: Cursor <cursoragent@cursor.com> * Harden MCP connected clients, revoke scope, and OAuth consent. List recoverable sessions with live refresh tokens, revoke only PATs, throttle registration alone, and block viewers from authorizing MCP. Co-authored-by: Cursor <cursoragent@cursor.com> * Simplify MCP OAuth route throttling to a single middleware group. Co-authored-by: Cursor <cursoragent@cursor.com> * Allow workspace viewers read-only MCP access with web policy writes. Mirror the web app: MCP connects on view + OAuth mcp:use, write tools enforce createPost/update/delete/manageAccounts/manageTeam, and demotion to Viewer keeps grants. Cover role denials, consent, and disconnect. Co-authored-by: Cursor <cursoragent@cursor.com> * Harden MCP tool authz with shared workspace helpers. Route ApiKey tools through AuthorizesMcpTool, fail closed on null user or policy argument, and resolve the current workspace before mutating. Co-authored-by: Cursor <cursoragent@cursor.com> * Drop redundant string casts on validated request data. Enum::from and validated() fields are already strings, so the casts add noise without changing behavior. Co-authored-by: Cursor <cursoragent@cursor.com> * Show only the current user's MCP connections in settings. Match API keys privacy: list and disconnect your own OAuth clients, not teammates' across the account. Co-authored-by: Cursor <cursoragent@cursor.com> * Cover LoadWorkspaceFromToken gaps and harden AuthorizesMcpTool tests. Co-authored-by: Cursor <cursoragent@cursor.com> * Drop redundant is_string guard before UpdatePostTool find. Co-authored-by: Cursor <cursoragent@cursor.com> * Refactor AppSidebar to always show MCP link and simplify route middleware definition in ai.php. The MCP link is now consistently displayed regardless of the current workspace state, and the route middleware syntax has been streamlined. * Refresh MCP connected clients with Inertia usePoll. Co-authored-by: Cursor <cursoragent@cursor.com> * Bump laravel/mcp to 0.9.1 and add the TryPost server icon. Requires laravel/boost 2.5 for the Icon attribute; expose images/trypost/icon.png on TryPostServer. Co-authored-by: Cursor <cursoragent@cursor.com> * Drop no-op ReflectionClass import in TryPostServerTest. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
385 lines
24 KiB
PHP
385 lines
24 KiB
PHP
<?php
|
||
|
||
return [
|
||
'title' => 'Налаштування',
|
||
'description' => 'Керуйте профілем та налаштуваннями облікового запису',
|
||
|
||
'hub' => [
|
||
'title' => 'Налаштування',
|
||
'description' => 'Виберіть, чим хочете керувати.',
|
||
'profile' => [
|
||
'title' => 'Профіль',
|
||
'description' => 'Оновіть особисті дані, пароль і налаштування сповіщень.',
|
||
],
|
||
'workspace' => [
|
||
'title' => 'Робочий простір',
|
||
'description' => 'Налаштуйте робочий простір, бренд, учасників і API-ключі.',
|
||
],
|
||
'account' => [
|
||
'title' => 'Обліковий запис',
|
||
'description' => 'Керуйте даними облікового запису, використанням і оплатою.',
|
||
],
|
||
],
|
||
|
||
'nav' => [
|
||
'profile' => 'Профіль',
|
||
'authentication' => 'Автентифікація',
|
||
'workspace' => 'Робочий простір',
|
||
'members' => 'Учасники',
|
||
'notifications' => 'Сповіщення',
|
||
'billing' => 'Оплата',
|
||
],
|
||
|
||
'notifications' => [
|
||
'title' => 'Налаштування сповіщень',
|
||
'heading' => 'Email-сповіщення',
|
||
'description' => 'Виберіть, які email-сповіщення ви хочете отримувати',
|
||
'post_published' => 'Пост опубліковано',
|
||
'post_published_description' => 'Отримуйте email, коли ваш пост успішно опубліковано',
|
||
'post_failed' => 'Помилка публікації',
|
||
'post_failed_description' => 'Отримуйте email, коли публікація поста не вдалася',
|
||
'account_disconnected' => 'Акаунт від’єднано',
|
||
'account_disconnected_description' => 'Отримуйте email, коли соціальний акаунт від’єднано',
|
||
'save' => 'Зберегти налаштування',
|
||
],
|
||
|
||
'profile' => [
|
||
'title' => 'Налаштування профілю',
|
||
'photo_heading' => 'Фото профілю',
|
||
'photo_description' => 'Завантажте фото профілю',
|
||
'heading' => 'Інформація профілю',
|
||
'description' => 'Оновіть ім’я та адресу email',
|
||
'avatar' => 'Аватар',
|
||
'name' => 'Ім’я',
|
||
'name_placeholder' => 'Повне ім’я',
|
||
'email' => 'Адреса email',
|
||
'email_placeholder' => 'Адреса email',
|
||
'email_unverified' => 'Вашу адресу email не підтверджено.',
|
||
'resend_verification' => 'Натисніть тут, щоб надіслати лист підтвердження ще раз.',
|
||
'verification_sent' => 'Нове посилання для підтвердження надіслано на вашу адресу email.',
|
||
'save' => 'Зберегти',
|
||
],
|
||
|
||
'authentication' => [
|
||
'title' => 'Автентифікація',
|
||
'page_title' => 'Налаштування автентифікації',
|
||
'sessions' => [
|
||
'title' => 'Активні сесії',
|
||
'description' => 'Якщо помітили щось підозріле, вийдіть з інших пристроїв.',
|
||
'unknown_browser' => 'Невідомий браузер',
|
||
'unknown_ip' => 'Невідомий IP',
|
||
'on' => 'на',
|
||
'active_now' => 'Активна зараз',
|
||
'log_out_others' => 'Вийти з інших пристроїв',
|
||
'modal_title' => 'Вийти з інших пристроїв',
|
||
'modal_description_password' => 'Введіть поточний пароль, щоб підтвердити вихід з інших сесій браузера.',
|
||
'modal_description_email' => 'Введіть адресу email, щоб підтвердити вихід з інших сесій браузера.',
|
||
'password_placeholder' => 'Поточний пароль',
|
||
'email_placeholder' => 'Email вашого облікового запису',
|
||
'cancel' => 'Скасувати',
|
||
'submit' => 'Вийти з інших пристроїв',
|
||
'email_mismatch' => 'Адреса email не збігається з вашим обліковим записом.',
|
||
'flash_logged_out' => 'Ви вийшли з інших пристроїв.',
|
||
],
|
||
'password' => [
|
||
'update_title' => 'Оновити пароль',
|
||
'set_title' => 'Встановити пароль',
|
||
'update_description' => 'Переконайтеся, що ваш обліковий запис використовує довгий випадковий пароль для безпеки.',
|
||
'set_description' => 'Додайте пароль, щоб входити без підключеного провайдера.',
|
||
'current_password' => 'Поточний пароль',
|
||
'new_password' => 'Новий пароль',
|
||
'confirm_password' => 'Підтвердіть пароль',
|
||
'save' => 'Зберегти пароль',
|
||
'set' => 'Встановити пароль',
|
||
],
|
||
'providers' => [
|
||
'title' => 'Підключені акаунти',
|
||
'description' => 'Входьте швидше через ці підключені провайдери.',
|
||
'connected' => 'Підключено',
|
||
'not_connected' => 'Не підключено',
|
||
'connect' => 'Підключити',
|
||
'disconnect' => 'Від’єднати',
|
||
'flash_disconnected' => ':provider успішно від’єднано.',
|
||
'flash_connected' => ':provider успішно підключено.',
|
||
'flash_already_linked' => 'Цей акаунт :provider уже прив’язано до іншого користувача.',
|
||
'flash_cannot_disconnect' => 'Ви не можете від’єднати свій єдиний спосіб входу. Спочатку встановіть пароль або підключіть іншого провайдера.',
|
||
],
|
||
],
|
||
|
||
'delete_account' => [
|
||
'heading' => 'Видалити обліковий запис',
|
||
'description' => 'Видаліть обліковий запис і всі його ресурси',
|
||
'warning' => 'Увага',
|
||
'warning_message' => 'Будьте обережні: цю дію не можна скасувати. Якщо ви власник цього облікового запису, запрошених учасників також буде назавжди видалено.',
|
||
'button' => 'Видалити обліковий запис',
|
||
'modal_title' => 'Ви впевнені, що хочете видалити обліковий запис?',
|
||
'modal_description_password' => 'Після видалення облікового запису всі його ресурси та дані також будуть назавжди видалені. Якщо ви власник облікового запису, запрошених учасників також буде назавжди видалено. Введіть пароль для підтвердження.',
|
||
'modal_description_email' => 'Після видалення облікового запису всі його ресурси та дані також будуть назавжди видалені. Якщо ви власник облікового запису, запрошених учасників також буде назавжди видалено. Введіть свою адресу email :email для підтвердження.',
|
||
'password' => 'Пароль',
|
||
'password_placeholder' => 'Пароль',
|
||
'email_placeholder' => 'Email вашого облікового запису',
|
||
'email_mismatch' => 'Адреса email не збігається з вашим обліковим записом.',
|
||
'cancel' => 'Скасувати',
|
||
'confirm' => 'Видалити обліковий запис',
|
||
],
|
||
|
||
'workspace' => [
|
||
'tabs' => [
|
||
'workspace' => 'Робочий простір',
|
||
'brand' => 'Бренд',
|
||
'users' => 'Учасники',
|
||
'api_keys' => 'API-ключі',
|
||
'mcp' => 'MCP',
|
||
],
|
||
'title' => 'Налаштування робочого простору',
|
||
'logo_heading' => 'Логотип робочого простору',
|
||
'logo_description' => 'Завантажте логотип для робочого простору',
|
||
'heading' => 'Назва робочого простору',
|
||
'description' => 'Оновіть назву робочого простору',
|
||
'members_heading' => 'Учасники',
|
||
'members_description' => 'Керуйте учасниками та запрошеннями робочого простору',
|
||
'name' => 'Назва',
|
||
'name_placeholder' => 'Мій робочий простір',
|
||
'save' => 'Зберегти',
|
||
'danger_description' => 'Незворотні дії.',
|
||
'delete_warning' => 'Увага',
|
||
'delete_title' => 'Видалити цей workspace',
|
||
'delete_description' => 'Назавжди видаляє цей workspace разом із постами, підключеними акаунтами та медіа. З вас стягуватиметься оплата на один workspace менше.',
|
||
'delete_description_self_hosted' => 'Назавжди видаляє цей workspace, його пости, підключені акаунти та медіа.',
|
||
'delete_only_description' => 'Ви не можете видалити свій єдиний workspace. Скасуйте підписку в розділі оплати, щоб перестати платити, або видаліть обліковий запис в Автентифікації, щоб скасувати оплату та назавжди видалити все.',
|
||
'delete_go_to_billing' => 'Перейти до оплати',
|
||
'delete_go_to_delete_account' => 'Видалити обліковий запис',
|
||
'delete_members_warning' => '{1}:count інший учасник втратить доступ. Учасники без іншого workspace у TryPost будуть назавжди видалені.|[2,*]:count інших учасників втратять доступ. Учасники без іншого workspace у TryPost будуть назавжди видалені.',
|
||
'delete_action' => 'Видалити workspace',
|
||
'delete_cancel' => 'Скасувати',
|
||
'delete_confirm_title' => 'Видалити workspace?',
|
||
'delete_confirm_description' => 'Це назавжди видалить workspace і всі його дані. Оплату буде оновлено з урахуванням одного workspace менше.',
|
||
'delete_confirm_description_self_hosted' => 'Це назавжди видалить workspace і всі його дані.',
|
||
],
|
||
|
||
'brand' => [
|
||
'title' => 'Бренд',
|
||
'description' => 'Налаштуйте ідентичність бренду для AI-контенту.',
|
||
'name' => 'Назва робочого простору',
|
||
'name_placeholder' => 'Мій бренд',
|
||
'website' => 'Вебсайт',
|
||
'website_placeholder' => 'https://yourbrand.com',
|
||
'brand_description' => 'Опис',
|
||
'brand_description_placeholder' => 'Розкажіть про ваш бренд, чим ви займаєтеся та хто ваша аудиторія...',
|
||
'voice' => 'Голос бренду',
|
||
'voice_description' => 'Виберіть риси, що визначають звучання вашого контенту.',
|
||
'voice_group' => [
|
||
'pov' => 'Точка зору',
|
||
'formality' => 'Формальність',
|
||
'energy' => 'Енергія',
|
||
'humor' => 'Гумор',
|
||
'attitude' => 'Настрій',
|
||
'warmth' => 'Теплота',
|
||
'confidence' => 'Впевненість',
|
||
'style' => 'Стиль',
|
||
],
|
||
'voice_trait' => [
|
||
'first_person' => 'Перша особа',
|
||
'second_person' => 'Друга особа (ви)',
|
||
'third_person' => 'Третя особа',
|
||
'formal' => 'Формальний',
|
||
'balanced' => 'Збалансований',
|
||
'casual' => 'Неформальний',
|
||
'calm' => 'Спокійний',
|
||
'moderate' => 'Помірний',
|
||
'enthusiastic' => 'Ентузіастичний',
|
||
'vibrant' => 'Яскравий',
|
||
'serious' => 'Серйозний',
|
||
'dry' => 'Сухий / тонкий',
|
||
'witty' => 'Дотепний',
|
||
'playful' => 'Грайливий',
|
||
'respectful' => 'Шанобливий',
|
||
'even_handed' => 'Об’єктивний',
|
||
'bold' => 'Сміливий',
|
||
'provocative' => 'Провокаційний',
|
||
'neutral' => 'Нейтральний',
|
||
'friendly' => 'Дружній',
|
||
'empathetic' => 'Емпатичний',
|
||
'humble' => 'Скромний',
|
||
'confident' => 'Впевнений',
|
||
'assertive' => 'Наполегливий',
|
||
'direct' => 'Прямий',
|
||
'concise' => 'Стислий',
|
||
'transparent' => 'Прозорий',
|
||
'no_hype' => 'Без хайпу',
|
||
'practical' => 'Практичний',
|
||
'data_driven' => 'На основі даних',
|
||
'storytelling' => 'Оповідний',
|
||
'inspirational' => 'Надихаючий',
|
||
'educational' => 'Освітній',
|
||
'technical' => 'Технічний',
|
||
'minimalist' => 'Мало emoji',
|
||
],
|
||
'brand_color' => 'Колір бренду',
|
||
'background_color' => 'Колір фону',
|
||
'text_color' => 'Колір тексту',
|
||
'font' => 'Шрифт',
|
||
'image_style' => 'Стиль зображення',
|
||
'image_style_description' => 'Візуальний стиль для AI-слайдів та обкладинок постів.',
|
||
'image_style_cinematic' => 'Кінематографічний',
|
||
'image_style_illustration' => 'Ілюстрація',
|
||
'image_style_isometric_3d' => 'Ізометричний',
|
||
'image_style_cartoon' => 'Мультяшний',
|
||
'image_style_typographic' => 'Типографічний',
|
||
'image_style_infographic' => 'Інфографіка',
|
||
'image_style_minimalist' => 'Мінімалістичний',
|
||
'image_style_mockup' => 'Мокап',
|
||
'content_language' => 'Мова контенту',
|
||
'content_language_description' => 'Мова для AI-підписів, хештегів і будь-якого тексту всередині згенерованих зображень або відео.',
|
||
'font_placeholder' => 'Виберіть шрифт…',
|
||
'font_search' => 'Пошук шрифту…',
|
||
'font_empty' => 'Шрифтів не знайдено.',
|
||
'language_placeholder' => 'Виберіть мову…',
|
||
'language_search' => 'Пошук мови…',
|
||
'language_empty' => 'Мову не знайдено.',
|
||
|
||
],
|
||
|
||
'members' => [
|
||
'title' => 'Учасники',
|
||
'heading' => 'Учасники команди',
|
||
'description' => 'Керуйте учасниками та запрошеннями цього робочого простору',
|
||
|
||
'cancel' => 'Скасувати',
|
||
'remove' => 'Видалити',
|
||
'make_role' => 'Призначити :role',
|
||
|
||
'invite' => [
|
||
'title' => 'Запросити учасника',
|
||
'description' => 'Надішліть email-запрошення, щоб додати співавторів',
|
||
'email' => 'Email',
|
||
'email_placeholder' => 'collaborator@email.com',
|
||
'role' => 'Роль',
|
||
'role_placeholder' => 'Виберіть роль',
|
||
'submit' => 'Надіслати запрошення',
|
||
],
|
||
|
||
'pending' => [
|
||
'title' => 'Очікуючі запрошення',
|
||
'description' => 'Запрошення, що очікують прийняття',
|
||
'empty' => 'Немає очікуючих запрошень',
|
||
],
|
||
|
||
'list' => [
|
||
'title' => 'Учасники',
|
||
'description' => 'Люди з доступом до цього робочого простору',
|
||
'empty' => 'Немає учасників, окрім власника',
|
||
],
|
||
|
||
'remove_modal' => [
|
||
'title' => 'Видалити учасника',
|
||
'description' => 'Ви впевнені, що хочете видалити цього учасника з робочого простору? Він втратить доступ до всіх ресурсів робочого простору.',
|
||
'action' => 'Видалити учасника',
|
||
],
|
||
|
||
'cancel_invite_modal' => [
|
||
'title' => 'Скасувати запрошення',
|
||
'description' => 'Ви впевнені, що хочете скасувати це запрошення?',
|
||
'action' => 'Скасувати запрошення',
|
||
],
|
||
|
||
'roles' => [
|
||
'owner' => 'Власник',
|
||
'admin' => 'Адміністратор',
|
||
'member' => 'Учасник',
|
||
'viewer' => 'Глядач',
|
||
],
|
||
|
||
'errors' => [
|
||
'invite_exists' => 'Запрошення для цієї адреси email уже існує.',
|
||
'email_belongs_to_account' => 'Цей email уже належить іншому обліковому запису TryPost. Попросіть робочу адресу email.',
|
||
],
|
||
|
||
'flash' => [
|
||
'invite_sent' => 'Запрошення успішно надіслано!',
|
||
'invite_deleted' => 'Запрошення видалено.',
|
||
'member_removed' => 'Учасника успішно видалено.',
|
||
'role_updated' => 'Роль учасника оновлено.',
|
||
'wrong_email' => 'Це запрошення для іншої адреси email.',
|
||
'already_member' => 'Ви вже є учасником цього робочого простору.',
|
||
'invite_accepted' => 'Ласкаво просимо! Тепер ви учасник робочого простору.',
|
||
'invite_workspace_gone' => 'Це запрошення більше не дійсне, оскільки робочий простір було видалено.',
|
||
'invite_declined' => 'Запрошення відхилено.',
|
||
],
|
||
],
|
||
|
||
'account' => [
|
||
'tabs' => [
|
||
'account' => 'Обліковий запис',
|
||
'usage' => 'Використання',
|
||
'billing' => 'Оплата',
|
||
],
|
||
'title' => 'Налаштування облікового запису',
|
||
'description' => 'Керуйте назвою облікового запису та email для оплати',
|
||
'name' => 'Назва облікового запису',
|
||
'name_placeholder' => 'Моя компанія',
|
||
'billing_email' => 'Email для оплати',
|
||
'billing_email_placeholder' => 'billing@company.com',
|
||
'billing_email_hint' => 'Цей email використовуватиметься для рахунків і повідомлень про оплату від Stripe.',
|
||
'submit' => 'Зберегти',
|
||
],
|
||
|
||
'flash' => [
|
||
'account_updated' => 'Обліковий запис успішно оновлено!',
|
||
'profile_updated' => 'Профіль успішно оновлено!',
|
||
'password_updated' => 'Пароль успішно оновлено!',
|
||
'workspace_updated' => 'Налаштування успішно оновлено!',
|
||
'photo_updated' => 'Фото успішно оновлено!',
|
||
'photo_deleted' => 'Фото успішно видалено!',
|
||
'delete_failed_billing' => 'Не вдалося скасувати підписку у платіжного провайдера. Нічого не видалено. Спробуйте ще раз або зверніться до підтримки.',
|
||
'logo_updated' => 'Логотип успішно завантажено!',
|
||
'logo_deleted' => 'Логотип успішно видалено!',
|
||
'notifications_updated' => 'Налаштування сповіщень оновлено!',
|
||
],
|
||
|
||
'api_keys' => [
|
||
'title' => 'API-ключі',
|
||
'page_title' => 'API-ключі',
|
||
'heading' => 'API-ключі',
|
||
'description' => 'Керуйте API-ключами для програмного доступу до робочого простору.',
|
||
'create' => 'Створити API-ключ',
|
||
'copy' => 'Копіювати',
|
||
'new_token_message' => 'Ваш новий API-ключ створено. Скопіюйте його зараз — ви більше не зможете його побачити.',
|
||
'table' => [
|
||
'name' => 'Назва',
|
||
'key' => 'Ключ',
|
||
'status' => 'Статус',
|
||
'expires' => 'Діє до',
|
||
'last_used' => 'Останнє використання',
|
||
'never' => 'Ніколи',
|
||
],
|
||
'actions' => [
|
||
'copy_id' => 'Копіювати ID API-ключа',
|
||
'copy_id_success' => 'ID API-ключа скопійовано в буфер обміну',
|
||
'delete' => 'Видалити',
|
||
],
|
||
'empty' => [
|
||
'title' => 'API-ключів ще немає',
|
||
'description' => 'Створіть API-ключ для програмного доступу до робочого простору.',
|
||
],
|
||
'delete_modal' => [
|
||
'title' => 'Видалити API-ключ',
|
||
'description' => 'Ви впевнені, що хочете видалити цей API-ключ? Усі додатки, що використовують цей ключ, негайно втратять доступ.',
|
||
'action' => 'Видалити API-ключ',
|
||
],
|
||
'create_dialog' => [
|
||
'title' => 'Створити API-ключ',
|
||
'description' => 'Створіть новий API-ключ для програмного доступу до робочого простору.',
|
||
'name' => 'Назва',
|
||
'name_placeholder' => 'напр. Production API Key',
|
||
'expires' => 'Дата закінчення (необов’язково)',
|
||
'expires_placeholder' => 'Без терміну дії',
|
||
'submit' => 'Створити',
|
||
'cancel' => 'Скасувати',
|
||
],
|
||
'flash' => [
|
||
'created' => 'API-ключ успішно створено!',
|
||
'deleted' => 'API-ключ успішно видалено!',
|
||
],
|
||
],
|
||
];
|