* 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
19 KiB
PHP
385 lines
19 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' => '이메일 알림',
|
|
'description' => '받고 싶은 이메일 알림을 선택하세요',
|
|
'post_published' => '게시물 게시됨',
|
|
'post_published_description' => '게시물이 성공적으로 게시되면 이메일을 받습니다',
|
|
'post_failed' => '게시물 실패',
|
|
'post_failed_description' => '게시물 게시에 실패하면 이메일을 받습니다',
|
|
'account_disconnected' => '계정 연결 해제됨',
|
|
'account_disconnected_description' => '소셜 계정 연결이 해제되면 이메일을 받습니다',
|
|
'save' => '설정 저장',
|
|
],
|
|
|
|
'profile' => [
|
|
'title' => '프로필 설정',
|
|
'photo_heading' => '프로필 사진',
|
|
'photo_description' => '프로필 사진을 업로드하세요',
|
|
'heading' => '프로필 정보',
|
|
'description' => '이름과 이메일 주소를 업데이트하세요',
|
|
'avatar' => '아바타',
|
|
'name' => '이름',
|
|
'name_placeholder' => '전체 이름',
|
|
'email' => '이메일 주소',
|
|
'email_placeholder' => '이메일 주소',
|
|
'email_unverified' => '이메일 주소가 인증되지 않았습니다.',
|
|
'resend_verification' => '인증 이메일을 다시 보내려면 여기를 클릭하세요.',
|
|
'verification_sent' => '이메일 주소로 새 인증 링크를 보냈습니다.',
|
|
'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' => '다른 브라우저 세션에서 로그아웃하려면 이메일 주소를 입력하여 확인하세요.',
|
|
'password_placeholder' => '현재 비밀번호',
|
|
'email_placeholder' => '계정 이메일',
|
|
'cancel' => '취소',
|
|
'submit' => '다른 기기에서 로그아웃',
|
|
'email_mismatch' => '이메일 주소가 계정과 일치하지 않습니다.',
|
|
'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을(를) 입력하세요.',
|
|
'password' => '비밀번호',
|
|
'password_placeholder' => '비밀번호',
|
|
'email_placeholder' => '계정 이메일',
|
|
'email_mismatch' => '이메일 주소가 계정과 일치하지 않습니다.',
|
|
'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' => '이 워크스페이스 삭제',
|
|
'delete_description' => '이 워크스페이스와 그 안의 모든 것(게시물, 연결된 계정, 미디어)을 영구 삭제합니다. 워크스페이스 하나만큼 요금이 줄어듭니다.',
|
|
'delete_description_self_hosted' => '이 워크스페이스와 게시물, 연결된 계정, 미디어를 영구 삭제합니다.',
|
|
'delete_only_description' => '유일한 워크스페이스는 삭제할 수 없습니다. 결제를 멈추려면 청구에서 구독을 취소하거나, 인증 설정에서 계정을 삭제해 결제를 취소하고 모든 데이터를 영구 삭제하세요.',
|
|
'delete_go_to_billing' => '결제로 이동',
|
|
'delete_go_to_delete_account' => '계정 삭제',
|
|
'delete_members_warning' => '{1}다른 멤버 :count명이 접근 권한을 잃습니다. 다른 TryPost 워크스페이스가 없는 멤버는 계정이 영구 삭제됩니다.|[2,*]다른 멤버 :count명이 접근 권한을 잃습니다. 다른 TryPost 워크스페이스가 없는 멤버는 계정이 영구 삭제됩니다.',
|
|
'delete_action' => '워크스페이스 삭제',
|
|
'delete_cancel' => '취소',
|
|
'delete_confirm_title' => '워크스페이스를 삭제할까요?',
|
|
'delete_confirm_description' => '워크스페이스와 모든 데이터가 영구 삭제됩니다. 결제는 워크스페이스가 하나 줄어든 상태로 업데이트됩니다.',
|
|
'delete_confirm_description_self_hosted' => '워크스페이스와 모든 데이터가 영구 삭제됩니다.',
|
|
],
|
|
|
|
'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' => '1인칭',
|
|
'second_person' => '2인칭 (당신)',
|
|
'third_person' => '3인칭',
|
|
'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' => '이모지 최소화',
|
|
],
|
|
'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_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_belongs_to_account' => '이 이메일은 이미 다른 TryPost 계정에 속해 있습니다. 전용 업무용 이메일을 사용해 주세요.',
|
|
],
|
|
|
|
'flash' => [
|
|
'invite_sent' => '초대가 성공적으로 전송되었습니다!',
|
|
'invite_deleted' => '초대가 삭제되었습니다.',
|
|
'member_removed' => '멤버가 성공적으로 제거되었습니다.',
|
|
'role_updated' => '멤버 역할이 업데이트되었습니다.',
|
|
'wrong_email' => '이 초대는 다른 이메일 주소를 위한 것입니다.',
|
|
'already_member' => '이미 이 워크스페이스의 멤버입니다.',
|
|
'invite_accepted' => '환영합니다! 이제 워크스페이스의 멤버입니다.',
|
|
'invite_workspace_gone' => '워크스페이스가 삭제되어 이 초대는 더 이상 유효하지 않습니다.',
|
|
'invite_declined' => '초대를 거절했습니다.',
|
|
],
|
|
],
|
|
|
|
'account' => [
|
|
'tabs' => [
|
|
'account' => '계정',
|
|
'usage' => '사용량',
|
|
'billing' => '결제',
|
|
],
|
|
'title' => '계정 설정',
|
|
'description' => '계정 이름과 결제 이메일을 관리하세요',
|
|
'name' => '계정 이름',
|
|
'name_placeholder' => '내 회사',
|
|
'billing_email' => '결제 이메일',
|
|
'billing_email_placeholder' => 'billing@company.com',
|
|
'billing_email_hint' => '이 이메일은 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' => 'API 키 ID 복사',
|
|
'copy_id_success' => 'API 키 ID가 클립보드에 복사되었습니다',
|
|
'delete' => '삭제',
|
|
],
|
|
'empty' => [
|
|
'title' => '아직 API 키가 없습니다',
|
|
'description' => '워크스페이스에 프로그래밍 방식으로 접근하려면 API 키를 만드세요.',
|
|
],
|
|
'delete_modal' => [
|
|
'title' => 'API 키 삭제',
|
|
'description' => '이 API 키를 삭제하시겠습니까? 이 키를 사용하는 모든 애플리케이션이 즉시 접근 권한을 잃게 됩니다.',
|
|
'action' => 'API 키 삭제',
|
|
],
|
|
'create_dialog' => [
|
|
'title' => 'API 키 만들기',
|
|
'description' => '워크스페이스에 프로그래밍 방식으로 접근하기 위한 새 API 키를 만드세요.',
|
|
'name' => '이름',
|
|
'name_placeholder' => '예: 프로덕션 API 키',
|
|
'expires' => '만료 날짜 (선택)',
|
|
'expires_placeholder' => '만료 없음',
|
|
'submit' => '만들기',
|
|
'cancel' => '취소',
|
|
],
|
|
'flash' => [
|
|
'created' => 'API 키가 성공적으로 생성되었습니다!',
|
|
'deleted' => 'API 키가 성공적으로 삭제되었습니다!',
|
|
],
|
|
],
|
|
];
|