trypost/lang/en/settings.php
Paulo Castellano 4d8353d758
MCP: workspace settings, viewer read access, and token access (#241)
* 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>
2026-08-06 09:54:51 -03:00

385 lines
17 KiB
PHP

<?php
return [
'title' => 'Settings',
'description' => 'Manage your profile and account settings',
'hub' => [
'title' => 'Settings',
'description' => 'Choose what you want to manage.',
'profile' => [
'title' => 'Profile',
'description' => 'Update your personal info, password, and notification preferences.',
],
'workspace' => [
'title' => 'Workspace',
'description' => 'Configure your workspace, brand, members, and API keys.',
],
'account' => [
'title' => 'Account',
'description' => 'Manage your account info, usage, and billing.',
],
],
'nav' => [
'profile' => 'Profile',
'authentication' => 'Authentication',
'workspace' => 'Workspace',
'members' => 'Members',
'notifications' => 'Notifications',
'billing' => 'Billing',
],
'notifications' => [
'title' => 'Notification preferences',
'heading' => 'Email notifications',
'description' => 'Choose which email notifications you want to receive',
'post_published' => 'Post published',
'post_published_description' => 'Receive an email when your post is published successfully',
'post_failed' => 'Post failed',
'post_failed_description' => 'Receive an email when your post fails to publish',
'account_disconnected' => 'Account disconnected',
'account_disconnected_description' => 'Receive an email when a social account is disconnected',
'save' => 'Save preferences',
],
'profile' => [
'title' => 'Profile settings',
'photo_heading' => 'Profile photo',
'photo_description' => 'Upload a profile photo',
'heading' => 'Profile information',
'description' => 'Update your name and email address',
'avatar' => 'Avatar',
'name' => 'Name',
'name_placeholder' => 'Full name',
'email' => 'Email address',
'email_placeholder' => 'Email address',
'email_unverified' => 'Your email address is unverified.',
'resend_verification' => 'Click here to resend the verification email.',
'verification_sent' => 'A new verification link has been sent to your email address.',
'save' => 'Save',
],
'authentication' => [
'title' => 'Authentication',
'page_title' => 'Authentication settings',
'sessions' => [
'title' => 'Active sessions',
'description' => 'If you notice anything suspicious, sign out of other devices.',
'unknown_browser' => 'Unknown browser',
'unknown_ip' => 'Unknown IP',
'on' => 'on',
'active_now' => 'Active now',
'log_out_others' => 'Log out other devices',
'modal_title' => 'Log out other devices',
'modal_description_password' => 'Enter your current password to confirm you want to log out other browser sessions.',
'modal_description_email' => 'Type your email address to confirm you want to log out other browser sessions.',
'password_placeholder' => 'Current password',
'email_placeholder' => 'Your account email',
'cancel' => 'Cancel',
'submit' => 'Log out other devices',
'email_mismatch' => 'The email address does not match your account.',
'flash_logged_out' => 'You have been logged out from other devices.',
],
'password' => [
'update_title' => 'Update password',
'set_title' => 'Set a password',
'update_description' => 'Ensure your account is using a long, random password to stay secure.',
'set_description' => 'Add a password so you can sign in without a connected provider.',
'current_password' => 'Current password',
'new_password' => 'New password',
'confirm_password' => 'Confirm password',
'save' => 'Save password',
'set' => 'Set password',
],
'providers' => [
'title' => 'Connected accounts',
'description' => 'Sign in faster with these connected providers.',
'connected' => 'Connected',
'not_connected' => 'Not connected',
'connect' => 'Connect',
'disconnect' => 'Disconnect',
'flash_disconnected' => ':provider disconnected successfully.',
'flash_connected' => ':provider connected successfully.',
'flash_already_linked' => 'That :provider account is already linked to another user.',
'flash_cannot_disconnect' => 'You cannot disconnect your only sign-in method. Set a password or connect another provider first.',
],
],
'delete_account' => [
'heading' => 'Delete account',
'description' => 'Delete your account and all of its resources',
'warning' => 'Warning',
'warning_message' => 'Please proceed with caution, this cannot be undone. If you own this account, invited members will also be permanently deleted.',
'button' => 'Delete account',
'modal_title' => 'Are you sure you want to delete your account?',
'modal_description_password' => 'Once your account is deleted, all of its resources and data will also be permanently deleted. If you own the account, invited members will be permanently deleted too. Please enter your password to confirm.',
'modal_description_email' => 'Once your account is deleted, all of its resources and data will also be permanently deleted. If you own the account, invited members will be permanently deleted too. Please type your email address :email to confirm.',
'password' => 'Password',
'password_placeholder' => 'Password',
'email_placeholder' => 'Your account email',
'email_mismatch' => 'The email address does not match your account.',
'cancel' => 'Cancel',
'confirm' => 'Delete account',
],
'workspace' => [
'tabs' => [
'workspace' => 'Workspace',
'brand' => 'Brand',
'users' => 'Members',
'api_keys' => 'API Keys',
'mcp' => 'MCP',
],
'title' => 'Workspace settings',
'logo_heading' => 'Workspace logo',
'logo_description' => 'Upload a logo for your workspace',
'heading' => 'Workspace name',
'description' => 'Update your workspace name',
'members_heading' => 'Members',
'members_description' => 'Manage workspace members and invitations',
'name' => 'Name',
'name_placeholder' => 'My Workspace',
'save' => 'Save',
'danger_description' => 'Irreversible actions.',
'delete_warning' => 'Warning',
'delete_title' => 'Delete this workspace',
'delete_description' => 'Permanently deletes this workspace and everything in it — posts, connected accounts, and media. You will be charged for one fewer workspace.',
'delete_description_self_hosted' => 'Permanently deletes this workspace, its posts, connected accounts, and media.',
'delete_only_description' => 'You cannot delete your only workspace. Cancel your subscription in billing to stop paying, or delete your account in Authentication settings to cancel billing and permanently remove everything.',
'delete_go_to_billing' => 'Go to billing',
'delete_go_to_delete_account' => 'Delete account',
'delete_members_warning' => '{1}:count other member will lose access. Members without another TryPost workspace are permanently deleted.|[2,*]:count other members will lose access. Members without another TryPost workspace are permanently deleted.',
'delete_action' => 'Delete workspace',
'delete_cancel' => 'Cancel',
'delete_confirm_title' => 'Delete workspace?',
'delete_confirm_description' => 'This permanently deletes the workspace and all of its data. Your billing will update to reflect one fewer workspace.',
'delete_confirm_description_self_hosted' => 'This permanently deletes the workspace and all of its data.',
],
'brand' => [
'title' => 'Brand',
'description' => 'Configure your brand identity for AI-generated content.',
'name' => 'Workspace name',
'name_placeholder' => 'My brand',
'website' => 'Website',
'website_placeholder' => 'https://yourbrand.com',
'brand_description' => 'Description',
'brand_description_placeholder' => 'Tell us about your brand, what you do, and who your audience is...',
'voice' => 'Brand voice',
'voice_description' => 'Pick the traits that define how your content sounds.',
'voice_group' => [
'pov' => 'Point of view',
'formality' => 'Formality',
'energy' => 'Energy',
'humor' => 'Humor',
'attitude' => 'Attitude',
'warmth' => 'Warmth',
'confidence' => 'Confidence',
'style' => 'Style',
],
'voice_trait' => [
'first_person' => 'First person',
'second_person' => 'Second person (you)',
'third_person' => 'Third person',
'formal' => 'Formal',
'balanced' => 'Balanced',
'casual' => 'Casual',
'calm' => 'Calm',
'moderate' => 'Moderate',
'enthusiastic' => 'Enthusiastic',
'vibrant' => 'Vibrant',
'serious' => 'Serious',
'dry' => 'Dry / subtle',
'witty' => 'Witty',
'playful' => 'Playful',
'respectful' => 'Respectful',
'even_handed' => 'Even-handed',
'bold' => 'Bold',
'provocative' => 'Provocative',
'neutral' => 'Neutral',
'friendly' => 'Friendly',
'empathetic' => 'Empathetic',
'humble' => 'Humble',
'confident' => 'Confident',
'assertive' => 'Assertive',
'direct' => 'Direct',
'concise' => 'Concise',
'transparent' => 'Transparent',
'no_hype' => 'No hype',
'practical' => 'Practical',
'data_driven' => 'Data-driven',
'storytelling' => 'Storytelling',
'inspirational' => 'Inspirational',
'educational' => 'Educational',
'technical' => 'Technical',
'minimalist' => 'Few emojis',
],
'brand_color' => 'Brand color',
'background_color' => 'Background color',
'text_color' => 'Text color',
'font' => 'Font',
'image_style' => 'Image style',
'image_style_description' => 'Visual style applied when generating slide and cover images for AI posts.',
'image_style_cinematic' => 'Cinematic',
'image_style_illustration' => 'Illustration',
'image_style_isometric_3d' => 'Isometric',
'image_style_cartoon' => 'Cartoon',
'image_style_typographic' => 'Typographic',
'image_style_infographic' => 'Infographic',
'image_style_minimalist' => 'Minimalist',
'image_style_mockup' => 'Mockup',
'content_language' => 'Content language',
'content_language_description' => 'Language used for AI-generated captions, hashtags, and any text inside generated images or videos.',
'font_placeholder' => 'Select a font…',
'font_search' => 'Search font…',
'font_empty' => 'No fonts match.',
'language_placeholder' => 'Select a language…',
'language_search' => 'Search language…',
'language_empty' => 'No language found.',
],
'members' => [
'title' => 'Members',
'heading' => 'Team members',
'description' => 'Manage members and invites for this workspace',
'cancel' => 'Cancel',
'remove' => 'Remove',
'make_role' => 'Make :role',
'invite' => [
'title' => 'Invite Member',
'description' => 'Send an email invite to add collaborators',
'email' => 'Email',
'email_placeholder' => 'collaborator@email.com',
'role' => 'Role',
'role_placeholder' => 'Select a role',
'submit' => 'Send Invite',
],
'pending' => [
'title' => 'Pending Invites',
'description' => 'Invites awaiting acceptance',
'empty' => 'No pending invites',
],
'list' => [
'title' => 'Members',
'description' => 'People with access to this workspace',
'empty' => 'No members besides the owner',
],
'remove_modal' => [
'title' => 'Remove member',
'description' => 'Are you sure you want to remove this member from the workspace? They will lose access to all workspace resources.',
'action' => 'Remove member',
],
'cancel_invite_modal' => [
'title' => 'Cancel invitation',
'description' => 'Are you sure you want to cancel this invitation?',
'action' => 'Cancel invitation',
],
'roles' => [
'owner' => 'Owner',
'admin' => 'Admin',
'member' => 'Member',
'viewer' => 'Viewer',
],
'errors' => [
'invite_exists' => 'An invite already exists for this email.',
'email_belongs_to_account' => 'This email already belongs to another TryPost account. Ask for a dedicated work email instead.',
],
'flash' => [
'invite_sent' => 'Invite sent successfully!',
'invite_deleted' => 'Invite deleted.',
'member_removed' => 'Member removed successfully.',
'role_updated' => 'Member role updated.',
'wrong_email' => 'This invite is for a different email address.',
'already_member' => 'You are already a member of this workspace.',
'invite_accepted' => 'Welcome! You are now a member of the workspace.',
'invite_workspace_gone' => 'This invite is no longer valid because the workspace was deleted.',
'invite_declined' => 'Invite declined.',
],
],
'account' => [
'tabs' => [
'account' => 'Account',
'usage' => 'Usage',
'billing' => 'Billing',
],
'title' => 'Account Settings',
'description' => 'Manage your account name and billing email',
'name' => 'Account Name',
'name_placeholder' => 'My Company',
'billing_email' => 'Billing Email',
'billing_email_placeholder' => 'billing@company.com',
'billing_email_hint' => 'This email will be used for invoices and billing communications from Stripe.',
'submit' => 'Save',
],
'flash' => [
'account_updated' => 'Account updated successfully!',
'profile_updated' => 'Profile updated successfully!',
'password_updated' => 'Password updated successfully!',
'workspace_updated' => 'Settings updated successfully!',
'photo_updated' => 'Photo updated successfully!',
'photo_deleted' => 'Photo removed successfully!',
'delete_failed_billing' => 'We could not cancel your subscription with the billing provider. Nothing was deleted. Please try again or contact support.',
'logo_updated' => 'Logo uploaded successfully!',
'logo_deleted' => 'Logo removed successfully!',
'notifications_updated' => 'Notification preferences updated!',
],
'api_keys' => [
'title' => 'API Keys',
'page_title' => 'API Keys',
'heading' => 'API Keys',
'description' => 'Manage API keys for programmatic access to your workspace.',
'create' => 'Create API Key',
'copy' => 'Copy',
'new_token_message' => 'Your new API key has been created. Copy it now — you won\'t be able to see it again.',
'table' => [
'name' => 'Name',
'key' => 'Key',
'status' => 'Status',
'expires' => 'Expires',
'last_used' => 'Last Used',
'never' => 'Never',
],
'actions' => [
'copy_id' => 'Copy API Key ID',
'copy_id_success' => 'API Key ID copied to clipboard',
'delete' => 'Delete',
],
'empty' => [
'title' => 'No API keys yet',
'description' => 'Create an API key to access your workspace programmatically.',
],
'delete_modal' => [
'title' => 'Delete API key',
'description' => 'Are you sure you want to delete this API key? Any applications using this key will lose access immediately.',
'action' => 'Delete API key',
],
'create_dialog' => [
'title' => 'Create API Key',
'description' => 'Create a new API key for programmatic access to your workspace.',
'name' => 'Name',
'name_placeholder' => 'e.g. Production API Key',
'expires' => 'Expiration date (optional)',
'expires_placeholder' => 'No expiration',
'submit' => 'Create',
'cancel' => 'Cancel',
],
'flash' => [
'created' => 'API key created successfully!',
'deleted' => 'API key deleted successfully!',
],
],
];