mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-03-13 09:57:24 +00:00
Compare commits
5 Commits
a35140bc5e
...
v1.16.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ed3358cbd | ||
|
|
c1e025b665 | ||
|
|
cf3d23ee31 | ||
|
|
e7d6c40452 | ||
|
|
216932e7f9 |
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@siteboon/claude-code-ui",
|
||||
"version": "1.16.3",
|
||||
"version": "1.16.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@siteboon/claude-code-ui",
|
||||
"version": "1.16.3",
|
||||
"version": "1.16.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.1.29",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@siteboon/claude-code-ui",
|
||||
"version": "1.16.3",
|
||||
"version": "1.16.4",
|
||||
"description": "A web-based UI for Claude Code CLI",
|
||||
"type": "module",
|
||||
"main": "server/index.js",
|
||||
@@ -33,14 +33,14 @@
|
||||
"release": "./release.sh"
|
||||
},
|
||||
"keywords": [
|
||||
"claude coode",
|
||||
"claude code",
|
||||
"ai",
|
||||
"anthropic",
|
||||
"ui",
|
||||
"mobile"
|
||||
],
|
||||
"author": "Claude Code UI Contributors",
|
||||
"license": "MIT",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.1.29",
|
||||
"@codemirror/lang-css": "^6.3.1",
|
||||
|
||||
133
server/index.js
133
server/index.js
@@ -178,6 +178,69 @@ const server = http.createServer(app);
|
||||
|
||||
const ptySessionsMap = new Map();
|
||||
const PTY_SESSION_TIMEOUT = 30 * 60 * 1000;
|
||||
const SHELL_URL_PARSE_BUFFER_LIMIT = 32768;
|
||||
const ANSI_ESCAPE_SEQUENCE_REGEX = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\))/g;
|
||||
const TRAILING_URL_PUNCTUATION_REGEX = /[)\]}>.,;:!?]+$/;
|
||||
|
||||
function stripAnsiSequences(value = '') {
|
||||
return value.replace(ANSI_ESCAPE_SEQUENCE_REGEX, '');
|
||||
}
|
||||
|
||||
function normalizeDetectedUrl(url) {
|
||||
if (!url || typeof url !== 'string') return null;
|
||||
|
||||
const cleaned = url.trim().replace(TRAILING_URL_PUNCTUATION_REGEX, '');
|
||||
if (!cleaned) return null;
|
||||
|
||||
try {
|
||||
const parsed = new URL(cleaned);
|
||||
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
||||
return null;
|
||||
}
|
||||
return parsed.toString();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function extractUrlsFromText(value = '') {
|
||||
const directMatches = value.match(/https?:\/\/[^\s<>"'`\\\x1b\x07]+/gi) || [];
|
||||
|
||||
// Handle wrapped terminal URLs split across lines by terminal width.
|
||||
const wrappedMatches = [];
|
||||
const continuationRegex = /^[A-Za-z0-9\-._~:/?#\[\]@!$&'()*+,;=%]+$/;
|
||||
const lines = value.split(/\r?\n/);
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
const startMatch = line.match(/https?:\/\/[^\s<>"'`\\\x1b\x07]+/i);
|
||||
if (!startMatch) continue;
|
||||
|
||||
let combined = startMatch[0];
|
||||
let j = i + 1;
|
||||
while (j < lines.length) {
|
||||
const continuation = lines[j].trim();
|
||||
if (!continuation) break;
|
||||
if (!continuationRegex.test(continuation)) break;
|
||||
combined += continuation;
|
||||
j++;
|
||||
}
|
||||
|
||||
wrappedMatches.push(combined.replace(/\r?\n\s*/g, ''));
|
||||
}
|
||||
|
||||
return Array.from(new Set([...directMatches, ...wrappedMatches]));
|
||||
}
|
||||
|
||||
function shouldAutoOpenUrlFromOutput(value = '') {
|
||||
const normalized = value.toLowerCase();
|
||||
return (
|
||||
normalized.includes('browser didn\'t open') ||
|
||||
normalized.includes('open this url') ||
|
||||
normalized.includes('continue in your browser') ||
|
||||
normalized.includes('press enter to open') ||
|
||||
normalized.includes('open_url:')
|
||||
);
|
||||
}
|
||||
|
||||
// Single WebSocket server that handles both paths
|
||||
const wss = new WebSocketServer({
|
||||
@@ -960,7 +1023,8 @@ function handleShellConnection(ws) {
|
||||
console.log('🐚 Shell client connected');
|
||||
let shellProcess = null;
|
||||
let ptySessionKey = null;
|
||||
let outputBuffer = [];
|
||||
let urlDetectionBuffer = '';
|
||||
const announcedAuthUrls = new Set();
|
||||
|
||||
ws.on('message', async (message) => {
|
||||
try {
|
||||
@@ -974,6 +1038,8 @@ function handleShellConnection(ws) {
|
||||
const provider = data.provider || 'claude';
|
||||
const initialCommand = data.initialCommand;
|
||||
const isPlainShell = data.isPlainShell || (!!initialCommand && !hasSession) || provider === 'plain-shell';
|
||||
urlDetectionBuffer = '';
|
||||
announcedAuthUrls.clear();
|
||||
|
||||
// Login commands (Claude/Cursor auth) should never reuse cached sessions
|
||||
const isLoginCommand = initialCommand && (
|
||||
@@ -1113,9 +1179,7 @@ function handleShellConnection(ws) {
|
||||
...process.env,
|
||||
TERM: 'xterm-256color',
|
||||
COLORTERM: 'truecolor',
|
||||
FORCE_COLOR: '3',
|
||||
// Override browser opening commands to echo URL for detection
|
||||
BROWSER: os.platform() === 'win32' ? 'echo "OPEN_URL:"' : 'echo "OPEN_URL:"'
|
||||
FORCE_COLOR: '3'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1145,38 +1209,47 @@ function handleShellConnection(ws) {
|
||||
if (session.ws && session.ws.readyState === WebSocket.OPEN) {
|
||||
let outputData = data;
|
||||
|
||||
// Check for various URL opening patterns
|
||||
const patterns = [
|
||||
// Direct browser opening commands
|
||||
/(?:xdg-open|open|start)\s+(https?:\/\/[^\s\x1b\x07]+)/g,
|
||||
// BROWSER environment variable override
|
||||
const cleanChunk = stripAnsiSequences(data);
|
||||
urlDetectionBuffer = `${urlDetectionBuffer}${cleanChunk}`.slice(-SHELL_URL_PARSE_BUFFER_LIMIT);
|
||||
|
||||
outputData = outputData.replace(
|
||||
/OPEN_URL:\s*(https?:\/\/[^\s\x1b\x07]+)/g,
|
||||
// Git and other tools opening URLs
|
||||
/Opening\s+(https?:\/\/[^\s\x1b\x07]+)/gi,
|
||||
// General URL patterns that might be opened
|
||||
/Visit:\s*(https?:\/\/[^\s\x1b\x07]+)/gi,
|
||||
/View at:\s*(https?:\/\/[^\s\x1b\x07]+)/gi,
|
||||
/Browse to:\s*(https?:\/\/[^\s\x1b\x07]+)/gi
|
||||
];
|
||||
'[INFO] Opening in browser: $1'
|
||||
);
|
||||
|
||||
patterns.forEach(pattern => {
|
||||
let match;
|
||||
while ((match = pattern.exec(data)) !== null) {
|
||||
const url = match[1];
|
||||
console.log('[DEBUG] Detected URL for opening:', url);
|
||||
const emitAuthUrl = (detectedUrl, autoOpen = false) => {
|
||||
const normalizedUrl = normalizeDetectedUrl(detectedUrl);
|
||||
if (!normalizedUrl) return;
|
||||
|
||||
// Send URL opening message to client
|
||||
const isNewUrl = !announcedAuthUrls.has(normalizedUrl);
|
||||
if (isNewUrl) {
|
||||
announcedAuthUrls.add(normalizedUrl);
|
||||
session.ws.send(JSON.stringify({
|
||||
type: 'url_open',
|
||||
url: url
|
||||
type: 'auth_url',
|
||||
url: normalizedUrl,
|
||||
autoOpen
|
||||
}));
|
||||
|
||||
// Replace the OPEN_URL pattern with a user-friendly message
|
||||
if (pattern.source.includes('OPEN_URL')) {
|
||||
outputData = outputData.replace(match[0], `[INFO] Opening in browser: ${url}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const normalizedDetectedUrls = extractUrlsFromText(urlDetectionBuffer)
|
||||
.map((url) => normalizeDetectedUrl(url))
|
||||
.filter(Boolean);
|
||||
|
||||
// Prefer the most complete URL if shorter prefix variants are also present.
|
||||
const dedupedDetectedUrls = Array.from(new Set(normalizedDetectedUrls)).filter((url, _, urls) =>
|
||||
!urls.some((otherUrl) => otherUrl !== url && otherUrl.startsWith(url))
|
||||
);
|
||||
|
||||
dedupedDetectedUrls.forEach((url) => emitAuthUrl(url, false));
|
||||
|
||||
if (shouldAutoOpenUrlFromOutput(cleanChunk) && dedupedDetectedUrls.length > 0) {
|
||||
const bestUrl = dedupedDetectedUrls.reduce((longest, current) =>
|
||||
current.length > longest.length ? current : longest
|
||||
);
|
||||
emitAuthUrl(bestUrl, true);
|
||||
}
|
||||
|
||||
// Send regular output
|
||||
session.ws.send(JSON.stringify({
|
||||
|
||||
@@ -57,9 +57,7 @@ function LoginModal({
|
||||
if (onComplete) {
|
||||
onComplete(exitCode);
|
||||
}
|
||||
if (exitCode === 0) {
|
||||
onClose();
|
||||
}
|
||||
// Keep modal open so users can read login output and close explicitly.
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -26,6 +26,31 @@ if (typeof document !== 'undefined') {
|
||||
document.head.appendChild(styleSheet);
|
||||
}
|
||||
|
||||
function fallbackCopyToClipboard(text) {
|
||||
if (!text || typeof document === 'undefined') return false;
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.setAttribute('readonly', '');
|
||||
textarea.style.position = 'fixed';
|
||||
textarea.style.opacity = '0';
|
||||
textarea.style.pointerEvents = 'none';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.focus();
|
||||
textarea.select();
|
||||
|
||||
let copied = false;
|
||||
try {
|
||||
copied = document.execCommand('copy');
|
||||
} catch {
|
||||
copied = false;
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell = false, onProcessComplete, minimal = false, autoConnect = false }) {
|
||||
const { t } = useTranslation('chat');
|
||||
const terminalRef = useRef(null);
|
||||
@@ -37,12 +62,15 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
const [isRestarting, setIsRestarting] = useState(false);
|
||||
const [lastSessionId, setLastSessionId] = useState(null);
|
||||
const [isConnecting, setIsConnecting] = useState(false);
|
||||
const [authUrl, setAuthUrl] = useState('');
|
||||
const [authUrlCopyStatus, setAuthUrlCopyStatus] = useState('idle');
|
||||
|
||||
const selectedProjectRef = useRef(selectedProject);
|
||||
const selectedSessionRef = useRef(selectedSession);
|
||||
const initialCommandRef = useRef(initialCommand);
|
||||
const isPlainShellRef = useRef(isPlainShell);
|
||||
const onProcessCompleteRef = useRef(onProcessComplete);
|
||||
const authUrlRef = useRef('');
|
||||
|
||||
useEffect(() => {
|
||||
selectedProjectRef.current = selectedProject;
|
||||
@@ -52,6 +80,42 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
onProcessCompleteRef.current = onProcessComplete;
|
||||
});
|
||||
|
||||
const openAuthUrlInBrowser = useCallback((url = authUrlRef.current) => {
|
||||
if (!url) return false;
|
||||
|
||||
const popup = window.open(url, '_blank', 'noopener,noreferrer');
|
||||
if (popup) {
|
||||
try {
|
||||
popup.opener = null;
|
||||
} catch {
|
||||
// Ignore cross-origin restrictions when trying to null opener
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}, []);
|
||||
|
||||
const copyAuthUrlToClipboard = useCallback(async (url = authUrlRef.current) => {
|
||||
if (!url) return false;
|
||||
|
||||
let copied = false;
|
||||
try {
|
||||
if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {
|
||||
await navigator.clipboard.writeText(url);
|
||||
copied = true;
|
||||
}
|
||||
} catch {
|
||||
copied = false;
|
||||
}
|
||||
|
||||
if (!copied) {
|
||||
copied = fallbackCopyToClipboard(url);
|
||||
}
|
||||
|
||||
return copied;
|
||||
}, []);
|
||||
|
||||
const connectWebSocket = useCallback(async () => {
|
||||
if (isConnecting || isConnected) return;
|
||||
|
||||
@@ -77,6 +141,9 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
ws.current.onopen = () => {
|
||||
setIsConnected(true);
|
||||
setIsConnecting(false);
|
||||
authUrlRef.current = '';
|
||||
setAuthUrl('');
|
||||
setAuthUrlCopyStatus('idle');
|
||||
|
||||
setTimeout(() => {
|
||||
if (fitAddon.current && terminal.current) {
|
||||
@@ -119,8 +186,16 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
if (terminal.current) {
|
||||
terminal.current.write(output);
|
||||
}
|
||||
} else if (data.type === 'auth_url' && data.url) {
|
||||
authUrlRef.current = data.url;
|
||||
setAuthUrl(data.url);
|
||||
setAuthUrlCopyStatus('idle');
|
||||
} else if (data.type === 'url_open') {
|
||||
window.open(data.url, '_blank');
|
||||
if (data.url) {
|
||||
authUrlRef.current = data.url;
|
||||
setAuthUrl(data.url);
|
||||
setAuthUrlCopyStatus('idle');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Shell] Error handling WebSocket message:', error, event.data);
|
||||
@@ -130,6 +205,7 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
ws.current.onclose = (event) => {
|
||||
setIsConnected(false);
|
||||
setIsConnecting(false);
|
||||
setAuthUrlCopyStatus('idle');
|
||||
|
||||
if (terminal.current) {
|
||||
terminal.current.clear();
|
||||
@@ -145,7 +221,7 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
setIsConnected(false);
|
||||
setIsConnecting(false);
|
||||
}
|
||||
}, [isConnecting, isConnected]);
|
||||
}, [isConnecting, isConnected, openAuthUrlInBrowser]);
|
||||
|
||||
const connectToShell = useCallback(() => {
|
||||
if (!isInitialized || isConnected || isConnecting) return;
|
||||
@@ -166,6 +242,9 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
|
||||
setIsConnected(false);
|
||||
setIsConnecting(false);
|
||||
authUrlRef.current = '';
|
||||
setAuthUrl('');
|
||||
setAuthUrlCopyStatus('idle');
|
||||
}, []);
|
||||
|
||||
const sessionDisplayName = useMemo(() => {
|
||||
@@ -201,6 +280,9 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
|
||||
setIsConnected(false);
|
||||
setIsInitialized(false);
|
||||
authUrlRef.current = '';
|
||||
setAuthUrl('');
|
||||
setAuthUrlCopyStatus('idle');
|
||||
|
||||
setTimeout(() => {
|
||||
setIsRestarting(false);
|
||||
@@ -272,7 +354,10 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
const webLinksAddon = new WebLinksAddon();
|
||||
|
||||
terminal.current.loadAddon(fitAddon.current);
|
||||
terminal.current.loadAddon(webLinksAddon);
|
||||
// Disable xterm link auto-detection in minimal (login) mode to avoid partial wrapped URL links.
|
||||
if (!minimal) {
|
||||
terminal.current.loadAddon(webLinksAddon);
|
||||
}
|
||||
// Note: ClipboardAddon removed - we handle clipboard operations manually in attachCustomKeyEventHandler
|
||||
|
||||
try {
|
||||
@@ -284,12 +369,41 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
terminal.current.open(terminalRef.current);
|
||||
|
||||
terminal.current.attachCustomKeyEventHandler((event) => {
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === 'c' && terminal.current.hasSelection()) {
|
||||
if (
|
||||
event.type === 'keydown' &&
|
||||
minimal &&
|
||||
isPlainShellRef.current &&
|
||||
authUrlRef.current &&
|
||||
!event.ctrlKey &&
|
||||
!event.metaKey &&
|
||||
!event.altKey &&
|
||||
event.key?.toLowerCase() === 'c'
|
||||
) {
|
||||
copyAuthUrlToClipboard(authUrlRef.current).catch(() => {});
|
||||
}
|
||||
|
||||
if (
|
||||
event.type === 'keydown' &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key?.toLowerCase() === 'c' &&
|
||||
terminal.current.hasSelection()
|
||||
) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
document.execCommand('copy');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === 'v') {
|
||||
if (
|
||||
event.type === 'keydown' &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key?.toLowerCase() === 'v'
|
||||
) {
|
||||
// Block native browser/xterm paste so clipboard data is only sent after
|
||||
// the explicit clipboard-read flow resolves (avoids duplicate pastes).
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
navigator.clipboard.readText().then(text => {
|
||||
if (ws.current && ws.current.readyState === WebSocket.OPEN) {
|
||||
ws.current.send(JSON.stringify({
|
||||
@@ -359,7 +473,7 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
terminal.current = null;
|
||||
}
|
||||
};
|
||||
}, [selectedProject?.path || selectedProject?.fullPath, isRestarting]);
|
||||
}, [selectedProject?.path || selectedProject?.fullPath, isRestarting, minimal, copyAuthUrlToClipboard]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!autoConnect || !isInitialized || isConnecting || isConnected) return;
|
||||
@@ -383,9 +497,47 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
}
|
||||
|
||||
if (minimal) {
|
||||
const hasAuthUrl = Boolean(authUrl);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full bg-gray-900">
|
||||
<div className="h-full w-full bg-gray-900 relative">
|
||||
<div ref={terminalRef} className="h-full w-full focus:outline-none" style={{ outline: 'none' }} />
|
||||
{hasAuthUrl && (
|
||||
<div className="absolute inset-x-0 bottom-14 z-20 border-t border-gray-700/80 bg-gray-900/95 p-3 backdrop-blur-sm">
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-xs text-gray-300">Open or copy the login URL:</p>
|
||||
<input
|
||||
type="text"
|
||||
value={authUrl}
|
||||
readOnly
|
||||
onClick={(event) => event.currentTarget.select()}
|
||||
className="w-full rounded border border-gray-600 bg-gray-800 px-2 py-1 text-xs text-gray-100 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
||||
aria-label="Authentication URL"
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
openAuthUrlInBrowser(authUrl);
|
||||
}}
|
||||
className="flex-1 rounded bg-blue-600 px-3 py-2 text-xs font-medium text-white hover:bg-blue-700"
|
||||
>
|
||||
Open URL
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={async () => {
|
||||
const copied = await copyAuthUrlToClipboard(authUrl);
|
||||
setAuthUrlCopyStatus(copied ? 'copied' : 'failed');
|
||||
}}
|
||||
className="flex-1 rounded bg-gray-700 px-3 py-2 text-xs font-medium text-white hover:bg-gray-600"
|
||||
>
|
||||
{authUrlCopyStatus === 'copied' ? 'Copied' : 'Copy URL'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -495,4 +647,4 @@ function Shell({ selectedProject, selectedSession, initialCommand, isPlainShell
|
||||
);
|
||||
}
|
||||
|
||||
export default Shell;
|
||||
export default Shell;
|
||||
|
||||
@@ -21,6 +21,13 @@ import enSidebar from './locales/en/sidebar.json';
|
||||
import enChat from './locales/en/chat.json';
|
||||
import enCodeEditor from './locales/en/codeEditor.json';
|
||||
|
||||
import koCommon from './locales/ko/common.json';
|
||||
import koSettings from './locales/ko/settings.json';
|
||||
import koAuth from './locales/ko/auth.json';
|
||||
import koSidebar from './locales/ko/sidebar.json';
|
||||
import koChat from './locales/ko/chat.json';
|
||||
import koCodeEditor from './locales/ko/codeEditor.json';
|
||||
|
||||
import zhCommon from './locales/zh-CN/common.json';
|
||||
import zhSettings from './locales/zh-CN/settings.json';
|
||||
import zhAuth from './locales/zh-CN/auth.json';
|
||||
@@ -60,6 +67,14 @@ i18n
|
||||
chat: enChat,
|
||||
codeEditor: enCodeEditor,
|
||||
},
|
||||
ko: {
|
||||
common: koCommon,
|
||||
settings: koSettings,
|
||||
auth: koAuth,
|
||||
sidebar: koSidebar,
|
||||
chat: koChat,
|
||||
codeEditor: koCodeEditor,
|
||||
},
|
||||
'zh-CN': {
|
||||
common: zhCommon,
|
||||
settings: zhSettings,
|
||||
|
||||
@@ -14,6 +14,11 @@ export const languages = [
|
||||
label: 'English',
|
||||
nativeName: 'English',
|
||||
},
|
||||
{
|
||||
value: 'ko',
|
||||
label: 'Korean',
|
||||
nativeName: '한국어',
|
||||
},
|
||||
{
|
||||
value: 'zh-CN',
|
||||
label: 'Simplified Chinese',
|
||||
|
||||
37
src/i18n/locales/ko/auth.json
Normal file
37
src/i18n/locales/ko/auth.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"login": {
|
||||
"title": "다시 오신 것을 환영합니다",
|
||||
"description": "Claude Code UI 계정에 로그인하세요",
|
||||
"username": "사용자명",
|
||||
"password": "비밀번호",
|
||||
"submit": "로그인",
|
||||
"loading": "로그인 중...",
|
||||
"errors": {
|
||||
"invalidCredentials": "사용자명 또는 비밀번호가 잘못되었습니다",
|
||||
"requiredFields": "모든 항목을 입력해주세요",
|
||||
"networkError": "네트워크 오류. 다시 시도해주세요."
|
||||
},
|
||||
"placeholders": {
|
||||
"username": "사용자명을 입력하세요",
|
||||
"password": "비밀번호를 입력하세요"
|
||||
}
|
||||
},
|
||||
"register": {
|
||||
"title": "계정 생성",
|
||||
"username": "사용자명",
|
||||
"password": "비밀번호",
|
||||
"confirmPassword": "비밀번호 확인",
|
||||
"submit": "계정 생성",
|
||||
"loading": "계정 생성 중...",
|
||||
"errors": {
|
||||
"passwordMismatch": "비밀번호가 일치하지 않습니다",
|
||||
"usernameTaken": "이미 사용 중인 사용자명입니다",
|
||||
"weakPassword": "비밀번호가 너무 약합니다"
|
||||
}
|
||||
},
|
||||
"logout": {
|
||||
"title": "로그아웃",
|
||||
"confirm": "정말 로그아웃하시겠습니까?",
|
||||
"button": "로그아웃"
|
||||
}
|
||||
}
|
||||
205
src/i18n/locales/ko/chat.json
Normal file
205
src/i18n/locales/ko/chat.json
Normal file
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"codeBlock": {
|
||||
"copy": "복사",
|
||||
"copied": "복사됨",
|
||||
"copyCode": "코드 복사"
|
||||
},
|
||||
"messageTypes": {
|
||||
"user": "U",
|
||||
"error": "오류",
|
||||
"tool": "도구",
|
||||
"claude": "Claude",
|
||||
"cursor": "Cursor",
|
||||
"codex": "Codex"
|
||||
},
|
||||
"tools": {
|
||||
"settings": "도구 설정",
|
||||
"error": "도구 오류",
|
||||
"result": "도구 결과",
|
||||
"viewParams": "입력 파라미터 보기",
|
||||
"viewRawParams": "Raw 파라미터 보기",
|
||||
"viewDiff": "편집 Diff 보기:",
|
||||
"creatingFile": "새 파일 생성:",
|
||||
"updatingTodo": "Todo 리스트 업데이트",
|
||||
"read": "읽기",
|
||||
"readFile": "파일 읽기",
|
||||
"updateTodo": "Todo 리스트 업데이트",
|
||||
"readTodo": "Todo 리스트 읽기",
|
||||
"searchResults": "결과"
|
||||
},
|
||||
"search": {
|
||||
"found": "{{count}}개의 {{type}} 발견",
|
||||
"file": "파일",
|
||||
"files": "파일",
|
||||
"pattern": "패턴:",
|
||||
"in": "위치:"
|
||||
},
|
||||
"fileOperations": {
|
||||
"updated": "파일이 업데이트되었습니다",
|
||||
"created": "파일이 생성되었습니다",
|
||||
"written": "파일이 작성되었습니다",
|
||||
"diff": "Diff",
|
||||
"newFile": "새 파일",
|
||||
"viewContent": "파일 내용 보기",
|
||||
"viewFullOutput": "전체 출력 보기 ({{count}}자)",
|
||||
"contentDisplayed": "파일 내용이 위의 Diff 보기에 표시됩니다"
|
||||
},
|
||||
"interactive": {
|
||||
"title": "대화형 프롬프트",
|
||||
"waiting": "CLI에서 응답을 기다리는 중",
|
||||
"instruction": "Claude가 실행 중인 터미널에서 옵션을 선택해주세요.",
|
||||
"selectedOption": "✓ Claude가 옵션 {{number}}을(를) 선택했습니다",
|
||||
"instructionDetail": "CLI에서 화살표 키 또는 숫자를 입력하여 이 옵션을 대화형으로 선택합니다."
|
||||
},
|
||||
"thinking": {
|
||||
"title": "생각 중...",
|
||||
"emoji": "💭 생각 중..."
|
||||
},
|
||||
"json": {
|
||||
"response": "JSON 응답"
|
||||
},
|
||||
"permissions": {
|
||||
"grant": "{{tool}}에 대한 권한 부여",
|
||||
"added": "권한이 추가되었습니다",
|
||||
"addTo": "{{entry}}을(를) 허용된 도구에 추가합니다.",
|
||||
"retry": "권한이 저장되었습니다. 도구를 사용하려면 요청을 재시도하세요.",
|
||||
"error": "권한을 업데이트할 수 없습니다. 다시 시도해주세요.",
|
||||
"openSettings": "설정 열기"
|
||||
},
|
||||
"todo": {
|
||||
"updated": "Todo 리스트가 업데이트되었습니다",
|
||||
"current": "현재 Todo 리스트"
|
||||
},
|
||||
"plan": {
|
||||
"viewPlan": "📋 구현 계획 보기",
|
||||
"title": "구현 계획"
|
||||
},
|
||||
"usageLimit": {
|
||||
"resetAt": "Claude 사용량 한도에 도달했습니다. 한도는 **{{time}} {{timezone}}** - {{date}}에 초기화됩니다"
|
||||
},
|
||||
"codex": {
|
||||
"permissionMode": "권한 모드",
|
||||
"modes": {
|
||||
"default": "기본 모드",
|
||||
"acceptEdits": "편집 허용",
|
||||
"bypassPermissions": "권한 우회",
|
||||
"plan": "Plan 모드"
|
||||
},
|
||||
"descriptions": {
|
||||
"default": "신뢰할 수 있는 명령어(ls, cat, grep, git status 등)만 자동 실행됩니다. 다른 명령어는 건너뜁니다. 워크스페이스에 쓰기 가능.",
|
||||
"acceptEdits": "워크스페이스 내에서 모든 명령어가 자동 실행됩니다. 샌드박스 내 완전 자동 모드.",
|
||||
"bypassPermissions": "제한 없는 전체 시스템 접근. 모든 명령어가 전체 디스크 및 네트워크 접근 권한으로 자동 실행됩니다. 주의해서 사용하세요.",
|
||||
"plan": "계획 모드 - 명령어가 실행되지 않습니다"
|
||||
},
|
||||
"technicalDetails": "기술 상세"
|
||||
},
|
||||
"input": {
|
||||
"placeholder": "/를 입력하여 명령어, @를 입력하여 파일, 또는 {{provider}}에게 무엇이든 물어보세요...",
|
||||
"placeholderDefault": "메시지를 입력하세요...",
|
||||
"disabled": "입력 비활성화",
|
||||
"attachFiles": "파일 첨부",
|
||||
"attachImages": "이미지 첨부",
|
||||
"send": "전송",
|
||||
"stop": "중지",
|
||||
"hintText": {
|
||||
"ctrlEnter": "Ctrl+Enter로 전송 • Shift+Enter로 줄바꿈 • Tab으로 모드 변경 • /로 슬래시 명령어",
|
||||
"enter": "Enter로 전송 • Shift+Enter로 줄바꿈 • Tab으로 모드 변경 • /로 슬래시 명령어"
|
||||
},
|
||||
"clickToChangeMode": "클릭하여 권한 모드 변경 (또는 입력창에서 Tab)",
|
||||
"showAllCommands": "모든 명령어 보기"
|
||||
},
|
||||
"thinkingMode": {
|
||||
"selector": {
|
||||
"title": "Thinking 모드",
|
||||
"description": "확장된 thinking은 Claude에게 대안을 평가할 시간을 더 줍니다",
|
||||
"active": "활성",
|
||||
"tip": "높은 thinking 모드는 시간이 더 걸리지만 더 철저한 분석을 제공합니다"
|
||||
},
|
||||
"modes": {
|
||||
"none": {
|
||||
"name": "Standard",
|
||||
"description": "일반 Claude 응답",
|
||||
"prefix": ""
|
||||
},
|
||||
"think": {
|
||||
"name": "Think",
|
||||
"description": "기본 확장 thinking",
|
||||
"prefix": "think"
|
||||
},
|
||||
"thinkHard": {
|
||||
"name": "Think Hard",
|
||||
"description": "더 철저한 평가",
|
||||
"prefix": "think hard"
|
||||
},
|
||||
"thinkHarder": {
|
||||
"name": "Think Harder",
|
||||
"description": "대안을 포함한 심층 분석",
|
||||
"prefix": "think harder"
|
||||
},
|
||||
"ultrathink": {
|
||||
"name": "Ultrathink",
|
||||
"description": "최대 thinking 예산",
|
||||
"prefix": "ultrathink"
|
||||
}
|
||||
},
|
||||
"buttonTitle": "Thinking 모드: {{mode}}"
|
||||
},
|
||||
"providerSelection": {
|
||||
"title": "AI 어시스턴트 선택",
|
||||
"description": "새 대화를 시작할 프로바이더를 선택하세요",
|
||||
"selectModel": "모델 선택",
|
||||
"providerInfo": {
|
||||
"anthropic": "by Anthropic",
|
||||
"openai": "by OpenAI",
|
||||
"cursorEditor": "AI 코드 에디터"
|
||||
},
|
||||
"readyPrompt": {
|
||||
"claude": "{{model}}로 Claude를 사용할 준비가 되었습니다. 아래에 메시지를 입력하세요.",
|
||||
"cursor": "{{model}}로 Cursor를 사용할 준비가 되었습니다. 아래에 메시지를 입력하세요.",
|
||||
"codex": "{{model}}로 Codex를 사용할 준비가 되었습니다. 아래에 메시지를 입력하세요.",
|
||||
"default": "시작하려면 위에서 프로바이더를 선택하세요"
|
||||
}
|
||||
},
|
||||
"session": {
|
||||
"continue": {
|
||||
"title": "대화 계속하기",
|
||||
"description": "코드에 대해 질문하거나, 변경을 요청하거나, 개발 작업에 도움을 받으세요"
|
||||
},
|
||||
"loading": {
|
||||
"olderMessages": "이전 메시지 로딩 중...",
|
||||
"sessionMessages": "세션 메시지 로딩 중..."
|
||||
},
|
||||
"messages": {
|
||||
"showingOf": "{{total}}개 중 {{shown}}개 표시",
|
||||
"scrollToLoad": "위로 스크롤하여 더 로드",
|
||||
"showingLast": "마지막 {{count}}개 메시지 표시 (총 {{total}}개)",
|
||||
"loadEarlier": "이전 메시지 로드"
|
||||
}
|
||||
},
|
||||
"shell": {
|
||||
"selectProject": {
|
||||
"title": "프로젝트 선택",
|
||||
"description": "해당 디렉토리에서 대화형 Shell을 열 프로젝트를 선택하세요"
|
||||
},
|
||||
"status": {
|
||||
"newSession": "새 세션",
|
||||
"initializing": "초기화 중...",
|
||||
"restarting": "재시작 중..."
|
||||
},
|
||||
"actions": {
|
||||
"disconnect": "연결 끊기",
|
||||
"disconnectTitle": "Shell 연결 끊기",
|
||||
"restart": "재시작",
|
||||
"restartTitle": "Shell 재시작 (먼저 연결 끊기)",
|
||||
"connect": "Shell에서 계속",
|
||||
"connectTitle": "Shell에 연결"
|
||||
},
|
||||
"loading": "터미널 로딩 중...",
|
||||
"connecting": "Shell에 연결 중...",
|
||||
"startSession": "새 Claude 세션 시작",
|
||||
"resumeSession": "세션 재개: {{displayName}}...",
|
||||
"runCommand": "{{projectName}}에서 {{command}} 실행",
|
||||
"startCli": "{{projectName}}에서 Claude CLI 시작",
|
||||
"defaultCommand": "명령어"
|
||||
}
|
||||
}
|
||||
30
src/i18n/locales/ko/codeEditor.json
Normal file
30
src/i18n/locales/ko/codeEditor.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"toolbar": {
|
||||
"changes": "변경사항",
|
||||
"previousChange": "이전 변경",
|
||||
"nextChange": "다음 변경",
|
||||
"hideDiff": "Diff 하이라이트 숨기기",
|
||||
"showDiff": "Diff 하이라이트 표시",
|
||||
"settings": "에디터 설정",
|
||||
"collapse": "에디터 접기",
|
||||
"expand": "에디터 전체 너비로 펼치기"
|
||||
},
|
||||
"loading": "{{fileName}} 로딩 중...",
|
||||
"header": {
|
||||
"showingChanges": "변경사항 표시"
|
||||
},
|
||||
"actions": {
|
||||
"download": "파일 다운로드",
|
||||
"save": "저장",
|
||||
"saving": "저장 중...",
|
||||
"saved": "저장됨!",
|
||||
"exitFullscreen": "전체화면 종료",
|
||||
"fullscreen": "전체화면",
|
||||
"close": "닫기"
|
||||
},
|
||||
"footer": {
|
||||
"lines": "줄:",
|
||||
"characters": "문자:",
|
||||
"shortcuts": "Ctrl+S로 저장 • Esc로 닫기"
|
||||
}
|
||||
}
|
||||
222
src/i18n/locales/ko/common.json
Normal file
222
src/i18n/locales/ko/common.json
Normal file
@@ -0,0 +1,222 @@
|
||||
{
|
||||
"buttons": {
|
||||
"save": "저장",
|
||||
"cancel": "취소",
|
||||
"delete": "삭제",
|
||||
"create": "생성",
|
||||
"edit": "편집",
|
||||
"close": "닫기",
|
||||
"confirm": "확인",
|
||||
"submit": "제출",
|
||||
"retry": "재시도",
|
||||
"refresh": "새로고침",
|
||||
"search": "검색",
|
||||
"clear": "지우기",
|
||||
"copy": "복사",
|
||||
"download": "다운로드",
|
||||
"upload": "업로드",
|
||||
"browse": "찾아보기"
|
||||
},
|
||||
"tabs": {
|
||||
"chat": "채팅",
|
||||
"shell": "Shell",
|
||||
"files": "파일",
|
||||
"git": "소스 관리",
|
||||
"tasks": "작업"
|
||||
},
|
||||
"status": {
|
||||
"loading": "로딩 중...",
|
||||
"success": "성공",
|
||||
"error": "오류",
|
||||
"failed": "실패",
|
||||
"pending": "대기 중",
|
||||
"completed": "완료",
|
||||
"inProgress": "진행 중"
|
||||
},
|
||||
"messages": {
|
||||
"savedSuccessfully": "저장되었습니다",
|
||||
"deletedSuccessfully": "삭제되었습니다",
|
||||
"updatedSuccessfully": "업데이트되었습니다",
|
||||
"operationFailed": "작업 실패",
|
||||
"networkError": "네트워크 오류. 연결을 확인해주세요.",
|
||||
"unauthorized": "인증되지 않았습니다. 로그인해주세요.",
|
||||
"notFound": "찾을 수 없음",
|
||||
"invalidInput": "잘못된 입력",
|
||||
"requiredField": "필수 항목입니다",
|
||||
"unknownError": "알 수 없는 오류가 발생했습니다"
|
||||
},
|
||||
"navigation": {
|
||||
"settings": "설정",
|
||||
"home": "홈",
|
||||
"back": "뒤로",
|
||||
"next": "다음",
|
||||
"previous": "이전",
|
||||
"logout": "로그아웃"
|
||||
},
|
||||
"common": {
|
||||
"language": "언어",
|
||||
"theme": "테마",
|
||||
"darkMode": "다크 모드",
|
||||
"lightMode": "라이트 모드",
|
||||
"name": "이름",
|
||||
"description": "설명",
|
||||
"enabled": "활성화",
|
||||
"disabled": "비활성화",
|
||||
"optional": "선택사항",
|
||||
"version": "버전",
|
||||
"select": "선택",
|
||||
"selectAll": "전체 선택",
|
||||
"deselectAll": "전체 해제"
|
||||
},
|
||||
"time": {
|
||||
"justNow": "방금 전",
|
||||
"minutesAgo": "{{count}}분 전",
|
||||
"hoursAgo": "{{count}}시간 전",
|
||||
"daysAgo": "{{count}}일 전",
|
||||
"yesterday": "어제"
|
||||
},
|
||||
"fileOperations": {
|
||||
"newFile": "새 파일",
|
||||
"newFolder": "새 폴더",
|
||||
"rename": "이름 변경",
|
||||
"move": "이동",
|
||||
"copyPath": "경로 복사",
|
||||
"openInEditor": "에디터에서 열기"
|
||||
},
|
||||
"mainContent": {
|
||||
"loading": "Claude Code UI 로딩 중",
|
||||
"settingUpWorkspace": "워크스페이스 설정 중...",
|
||||
"chooseProject": "프로젝트 선택",
|
||||
"selectProjectDescription": "사이드바에서 프로젝트를 선택하여 Claude와 코딩을 시작하세요. 각 프로젝트에는 채팅 세션과 파일 히스토리가 포함됩니다.",
|
||||
"tip": "팁",
|
||||
"createProjectMobile": "위의 메뉴 버튼을 눌러 프로젝트에 접근하세요",
|
||||
"createProjectDesktop": "사이드바의 폴더 아이콘을 클릭하여 새 프로젝트를 생성하세요",
|
||||
"newSession": "새 세션",
|
||||
"untitledSession": "제목 없는 세션",
|
||||
"projectFiles": "프로젝트 파일"
|
||||
},
|
||||
"fileTree": {
|
||||
"loading": "파일 로딩 중...",
|
||||
"files": "파일",
|
||||
"simpleView": "간단히 보기",
|
||||
"compactView": "컴팩트 보기",
|
||||
"detailedView": "상세히 보기",
|
||||
"searchPlaceholder": "파일 및 폴더 검색...",
|
||||
"clearSearch": "검색 지우기",
|
||||
"name": "이름",
|
||||
"size": "크기",
|
||||
"modified": "수정일",
|
||||
"permissions": "권한",
|
||||
"noFilesFound": "파일을 찾을 수 없음",
|
||||
"checkProjectPath": "프로젝트 경로가 접근 가능한지 확인하세요",
|
||||
"noMatchesFound": "일치하는 항목 없음",
|
||||
"tryDifferentSearch": "다른 검색어를 시도하거나 검색을 지우세요",
|
||||
"justNow": "방금 전",
|
||||
"minAgo": "{{count}}분 전",
|
||||
"hoursAgo": "{{count}}시간 전",
|
||||
"daysAgo": "{{count}}일 전"
|
||||
},
|
||||
"projectWizard": {
|
||||
"title": "새 프로젝트 생성",
|
||||
"steps": {
|
||||
"type": "유형",
|
||||
"configure": "설정",
|
||||
"confirm": "확인"
|
||||
},
|
||||
"step1": {
|
||||
"question": "이미 워크스페이스가 있으신가요, 아니면 새로 생성하시겠습니까?",
|
||||
"existing": {
|
||||
"title": "기존 워크스페이스",
|
||||
"description": "서버에 이미 워크스페이스가 있고 프로젝트 목록에 추가만 하면 됩니다"
|
||||
},
|
||||
"new": {
|
||||
"title": "새 워크스페이스",
|
||||
"description": "새 워크스페이스를 생성하고, 선택적으로 GitHub 저장소에서 clone합니다"
|
||||
}
|
||||
},
|
||||
"step2": {
|
||||
"existingPath": "워크스페이스 경로",
|
||||
"newPath": "워크스페이스 경로",
|
||||
"existingPlaceholder": "/path/to/existing/workspace",
|
||||
"newPlaceholder": "/path/to/new/workspace",
|
||||
"existingHelp": "기존 워크스페이스 디렉토리의 전체 경로",
|
||||
"newHelp": "워크스페이스 디렉토리의 전체 경로",
|
||||
"githubUrl": "GitHub URL (선택사항)",
|
||||
"githubPlaceholder": "https://github.com/username/repository",
|
||||
"githubHelp": "선택사항: 저장소를 clone하려면 GitHub URL을 입력하세요",
|
||||
"githubAuth": "GitHub 인증 (선택사항)",
|
||||
"githubAuthHelp": "비공개 저장소에만 필요합니다. 공개 저장소는 인증 없이 clone할 수 있습니다.",
|
||||
"loadingTokens": "저장된 토큰 로딩 중...",
|
||||
"storedToken": "저장된 토큰",
|
||||
"newToken": "새 토큰",
|
||||
"nonePublic": "없음 (공개)",
|
||||
"selectToken": "토큰 선택",
|
||||
"selectTokenPlaceholder": "-- 토큰 선택 --",
|
||||
"tokenPlaceholder": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"tokenHelp": "이 토큰은 이 작업에만 사용됩니다",
|
||||
"publicRepoInfo": "공개 저장소는 인증이 필요하지 않습니다. 공개 저장소를 clone하는 경우 토큰을 생략할 수 있습니다.",
|
||||
"noTokensHelp": "저장된 토큰이 없습니다. 설정 → API Keys에서 토큰을 추가하면 재사용이 편리합니다.",
|
||||
"optionalTokenPublic": "GitHub 토큰 (공개 저장소는 선택사항)",
|
||||
"tokenPublicPlaceholder": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (공개 저장소는 비워두세요)"
|
||||
},
|
||||
"step3": {
|
||||
"reviewConfig": "설정 검토",
|
||||
"workspaceType": "워크스페이스 유형:",
|
||||
"existingWorkspace": "기존 워크스페이스",
|
||||
"newWorkspace": "새 워크스페이스",
|
||||
"path": "경로:",
|
||||
"cloneFrom": "Clone 소스:",
|
||||
"authentication": "인증:",
|
||||
"usingStoredToken": "저장된 토큰 사용:",
|
||||
"usingProvidedToken": "제공된 토큰 사용",
|
||||
"noAuthentication": "인증 없음",
|
||||
"sshKey": "SSH 키",
|
||||
"existingInfo": "워크스페이스가 프로젝트 목록에 추가되며 Claude/Cursor 세션에서 사용할 수 있습니다.",
|
||||
"newWithClone": "이 폴더에 저장소가 clone됩니다.",
|
||||
"newEmpty": "워크스페이스가 프로젝트 목록에 추가되며 Claude/Cursor 세션에서 사용할 수 있습니다.",
|
||||
"cloningRepository": "저장소 clone 중..."
|
||||
},
|
||||
"buttons": {
|
||||
"cancel": "취소",
|
||||
"back": "뒤로",
|
||||
"next": "다음",
|
||||
"createProject": "프로젝트 생성",
|
||||
"creating": "생성 중...",
|
||||
"cloning": "Clone 중..."
|
||||
},
|
||||
"errors": {
|
||||
"selectType": "기존 워크스페이스를 사용할지 새로 생성할지 선택해주세요",
|
||||
"providePath": "워크스페이스 경로를 입력해주세요",
|
||||
"failedToCreate": "워크스페이스 생성 실패",
|
||||
"failedToCreateFolder": "폴더 생성 실패"
|
||||
}
|
||||
},
|
||||
"versionUpdate": {
|
||||
"title": "업데이트 가능",
|
||||
"newVersionReady": "새 버전이 준비되었습니다",
|
||||
"currentVersion": "현재 버전",
|
||||
"latestVersion": "최신 버전",
|
||||
"whatsNew": "새로운 기능:",
|
||||
"viewFullRelease": "전체 릴리스 보기",
|
||||
"updateProgress": "업데이트 진행 상황:",
|
||||
"manualUpgrade": "수동 업그레이드:",
|
||||
"manualUpgradeHint": "또는 \"지금 업데이트\"를 클릭하여 자동으로 업데이트합니다.",
|
||||
"updateCompleted": "업데이트가 완료되었습니다!",
|
||||
"restartServer": "변경사항을 적용하려면 서버를 재시작하세요.",
|
||||
"updateFailed": "업데이트 실패",
|
||||
"buttons": {
|
||||
"close": "닫기",
|
||||
"later": "나중에",
|
||||
"copyCommand": "명령어 복사",
|
||||
"updateNow": "지금 업데이트",
|
||||
"updating": "업데이트 중..."
|
||||
},
|
||||
"ariaLabels": {
|
||||
"closeModal": "버전 업그레이드 모달 닫기",
|
||||
"showSidebar": "사이드바 표시",
|
||||
"settings": "설정",
|
||||
"updateAvailable": "업데이트 가능",
|
||||
"closeSidebar": "사이드바 닫기"
|
||||
}
|
||||
}
|
||||
}
|
||||
418
src/i18n/locales/ko/settings.json
Normal file
418
src/i18n/locales/ko/settings.json
Normal file
@@ -0,0 +1,418 @@
|
||||
{
|
||||
"title": "설정",
|
||||
"tabs": {
|
||||
"account": "계정",
|
||||
"permissions": "권한",
|
||||
"mcpServers": "MCP 서버",
|
||||
"appearance": "외관"
|
||||
},
|
||||
"account": {
|
||||
"title": "계정",
|
||||
"language": "언어",
|
||||
"languageLabel": "표시 언어",
|
||||
"languageDescription": "인터페이스에 사용할 언어를 선택하세요",
|
||||
"username": "사용자명",
|
||||
"email": "이메일",
|
||||
"profile": "프로필",
|
||||
"changePassword": "비밀번호 변경"
|
||||
},
|
||||
"mcp": {
|
||||
"title": "MCP 서버",
|
||||
"addServer": "서버 추가",
|
||||
"editServer": "서버 편집",
|
||||
"deleteServer": "서버 삭제",
|
||||
"serverName": "서버 이름",
|
||||
"serverType": "서버 유형",
|
||||
"config": "설정",
|
||||
"testConnection": "연결 테스트",
|
||||
"status": "상태",
|
||||
"connected": "연결됨",
|
||||
"disconnected": "연결 끊김",
|
||||
"scope": {
|
||||
"label": "범위",
|
||||
"user": "사용자",
|
||||
"project": "프로젝트"
|
||||
}
|
||||
},
|
||||
"appearance": {
|
||||
"title": "외관",
|
||||
"theme": "테마",
|
||||
"codeEditor": "코드 에디터",
|
||||
"editorTheme": "에디터 테마",
|
||||
"wordWrap": "자동 줄바꿈",
|
||||
"showMinimap": "미니맵 표시",
|
||||
"lineNumbers": "줄 번호",
|
||||
"fontSize": "글꼴 크기"
|
||||
},
|
||||
"actions": {
|
||||
"saveChanges": "변경사항 저장",
|
||||
"resetToDefaults": "기본값으로 초기화",
|
||||
"cancelChanges": "변경 취소"
|
||||
},
|
||||
"quickSettings": {
|
||||
"title": "빠른 설정",
|
||||
"sections": {
|
||||
"appearance": "외관",
|
||||
"toolDisplay": "도구 표시",
|
||||
"viewOptions": "보기 옵션",
|
||||
"inputSettings": "입력 설정",
|
||||
"whisperDictation": "Whisper 음성 인식"
|
||||
},
|
||||
"darkMode": "다크 모드",
|
||||
"autoExpandTools": "도구 자동 펼치기",
|
||||
"showRawParameters": "Raw 파라미터 표시",
|
||||
"showThinking": "생각 과정 표시",
|
||||
"autoScrollToBottom": "자동 스크롤",
|
||||
"sendByCtrlEnter": "Ctrl+Enter로 전송",
|
||||
"sendByCtrlEnterDescription": "활성화하면 Enter 대신 Ctrl+Enter로 메시지를 전송합니다. IME 사용자가 실수로 전송하는 것을 방지하는 데 유용합니다.",
|
||||
"dragHandle": {
|
||||
"dragging": "드래그 핸들",
|
||||
"closePanel": "설정 패널 닫기",
|
||||
"openPanel": "설정 패널 열기",
|
||||
"draggingStatus": "드래그 중...",
|
||||
"toggleAndMove": "클릭하여 토글, 드래그하여 이동"
|
||||
},
|
||||
"whisper": {
|
||||
"modes": {
|
||||
"default": "기본 모드",
|
||||
"defaultDescription": "음성을 그대로 텍스트로 변환",
|
||||
"prompt": "프롬프트 향상",
|
||||
"promptDescription": "거친 아이디어를 명확하고 상세한 AI 프롬프트로 변환",
|
||||
"vibe": "Vibe 모드",
|
||||
"vibeDescription": "아이디어를 상세한 에이전트 지침 형식으로 변환"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mainTabs": {
|
||||
"agents": "에이전트",
|
||||
"appearance": "외관",
|
||||
"git": "Git",
|
||||
"apiTokens": "API & 토큰",
|
||||
"tasks": "작업"
|
||||
},
|
||||
"appearanceSettings": {
|
||||
"darkMode": {
|
||||
"label": "다크 모드",
|
||||
"description": "라이트/다크 테마 전환"
|
||||
},
|
||||
"projectSorting": {
|
||||
"label": "프로젝트 정렬",
|
||||
"description": "사이드바에서 프로젝트 정렬 방식",
|
||||
"alphabetical": "알파벳순",
|
||||
"recentActivity": "최근 활동순"
|
||||
},
|
||||
"codeEditor": {
|
||||
"title": "코드 에디터",
|
||||
"theme": {
|
||||
"label": "에디터 테마",
|
||||
"description": "코드 에디터의 기본 테마"
|
||||
},
|
||||
"wordWrap": {
|
||||
"label": "자동 줄바꿈",
|
||||
"description": "에디터에서 기본적으로 자동 줄바꿈 활성화"
|
||||
},
|
||||
"showMinimap": {
|
||||
"label": "미니맵 표시",
|
||||
"description": "Diff 보기에서 쉬운 탐색을 위한 미니맵 표시"
|
||||
},
|
||||
"lineNumbers": {
|
||||
"label": "줄 번호 표시",
|
||||
"description": "에디터에 줄 번호 표시"
|
||||
},
|
||||
"fontSize": {
|
||||
"label": "글꼴 크기",
|
||||
"description": "에디터 글꼴 크기 (픽셀)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mcpForm": {
|
||||
"title": {
|
||||
"add": "MCP 서버 추가",
|
||||
"edit": "MCP 서버 편집"
|
||||
},
|
||||
"importMode": {
|
||||
"form": "폼 입력",
|
||||
"json": "JSON 가져오기"
|
||||
},
|
||||
"scope": {
|
||||
"label": "범위",
|
||||
"userGlobal": "사용자 (전역)",
|
||||
"projectLocal": "프로젝트 (로컬)",
|
||||
"userDescription": "사용자 범위: 모든 프로젝트에서 사용 가능",
|
||||
"projectDescription": "로컬 범위: 선택한 프로젝트에서만 사용 가능",
|
||||
"cannotChange": "기존 서버를 편집할 때는 범위를 변경할 수 없습니다"
|
||||
},
|
||||
"fields": {
|
||||
"serverName": "서버 이름",
|
||||
"transportType": "전송 유형",
|
||||
"command": "명령어",
|
||||
"arguments": "인수 (한 줄에 하나씩)",
|
||||
"jsonConfig": "JSON 설정",
|
||||
"url": "URL",
|
||||
"envVars": "환경 변수 (KEY=value, 한 줄에 하나씩)",
|
||||
"headers": "헤더 (KEY=value, 한 줄에 하나씩)",
|
||||
"selectProject": "프로젝트 선택..."
|
||||
},
|
||||
"placeholders": {
|
||||
"serverName": "my-server"
|
||||
},
|
||||
"validation": {
|
||||
"missingType": "필수 항목 누락: type",
|
||||
"stdioRequiresCommand": "stdio 유형은 command 필드가 필요합니다",
|
||||
"httpRequiresUrl": "{{type}} 유형은 url 필드가 필요합니다",
|
||||
"invalidJson": "잘못된 JSON 형식",
|
||||
"jsonHelp": "MCP 서버 설정을 JSON 형식으로 붙여넣으세요. 예시:",
|
||||
"jsonExampleStdio": "• stdio: {\"type\":\"stdio\",\"command\":\"npx\",\"args\":[\"@upstash/context7-mcp\"]}",
|
||||
"jsonExampleHttp": "• http/sse: {\"type\":\"http\",\"url\":\"https://api.example.com/mcp\"}"
|
||||
},
|
||||
"configDetails": "설정 상세 ({{configFile}}에서)",
|
||||
"projectPath": "경로: {{path}}",
|
||||
"actions": {
|
||||
"cancel": "취소",
|
||||
"saving": "저장 중...",
|
||||
"addServer": "서버 추가",
|
||||
"updateServer": "서버 업데이트"
|
||||
}
|
||||
},
|
||||
"saveStatus": {
|
||||
"success": "설정이 저장되었습니다!",
|
||||
"error": "설정 저장 실패",
|
||||
"saving": "저장 중..."
|
||||
},
|
||||
"footerActions": {
|
||||
"save": "설정 저장",
|
||||
"cancel": "취소"
|
||||
},
|
||||
"git": {
|
||||
"title": "Git 설정",
|
||||
"description": "커밋을 위한 Git 정보를 설정합니다. 이 설정은 git config --global로 전역 적용됩니다",
|
||||
"name": {
|
||||
"label": "Git 이름",
|
||||
"help": "Git 커밋에 사용될 이름"
|
||||
},
|
||||
"email": {
|
||||
"label": "Git 이메일",
|
||||
"help": "Git 커밋에 사용될 이메일"
|
||||
},
|
||||
"actions": {
|
||||
"save": "설정 저장",
|
||||
"saving": "저장 중..."
|
||||
},
|
||||
"status": {
|
||||
"success": "저장 완료"
|
||||
}
|
||||
},
|
||||
"apiKeys": {
|
||||
"title": "API 키",
|
||||
"description": "다른 애플리케이션에서 외부 API에 접근하기 위한 API 키를 생성합니다.",
|
||||
"newKey": {
|
||||
"alertTitle": "⚠️ API 키를 저장하세요",
|
||||
"alertMessage": "이 키는 지금만 볼 수 있습니다. 안전하게 보관하세요.",
|
||||
"iveSavedIt": "저장했습니다"
|
||||
},
|
||||
"form": {
|
||||
"placeholder": "API 키 이름 (예: Production Server)",
|
||||
"createButton": "생성",
|
||||
"cancelButton": "취소"
|
||||
},
|
||||
"newButton": "새 API 키",
|
||||
"empty": "생성된 API 키가 없습니다.",
|
||||
"list": {
|
||||
"created": "생성일:",
|
||||
"lastUsed": "마지막 사용:"
|
||||
},
|
||||
"confirmDelete": "이 API 키를 삭제하시겠습니까?",
|
||||
"status": {
|
||||
"active": "활성",
|
||||
"inactive": "비활성"
|
||||
},
|
||||
"github": {
|
||||
"title": "GitHub 토큰",
|
||||
"description": "외부 API를 통해 비공개 저장소를 clone하기 위한 GitHub Personal Access Token을 추가합니다.",
|
||||
"descriptionAlt": "비공개 저장소를 clone하기 위한 GitHub Personal Access Token을 추가합니다. 저장하지 않고 API 요청에 직접 토큰을 전달할 수도 있습니다.",
|
||||
"addButton": "토큰 추가",
|
||||
"form": {
|
||||
"namePlaceholder": "토큰 이름 (예: Personal Repos)",
|
||||
"tokenPlaceholder": "GitHub Personal Access Token (ghp_...)",
|
||||
"descriptionPlaceholder": "설명 (선택사항)",
|
||||
"addButton": "토큰 추가",
|
||||
"cancelButton": "취소",
|
||||
"howToCreate": "GitHub Personal Access Token 생성 방법 →"
|
||||
},
|
||||
"empty": "추가된 GitHub 토큰이 없습니다.",
|
||||
"added": "추가일:",
|
||||
"confirmDelete": "이 GitHub 토큰을 삭제하시겠습니까?"
|
||||
},
|
||||
"apiDocsLink": "API 문서",
|
||||
"documentation": {
|
||||
"title": "외부 API 문서",
|
||||
"description": "외부 API를 사용하여 애플리케이션에서 Claude/Cursor 세션을 트리거하는 방법을 알아보세요.",
|
||||
"viewLink": "API 문서 보기 →"
|
||||
},
|
||||
"loading": "로딩 중...",
|
||||
"version": {
|
||||
"updateAvailable": "업데이트 가능: v{{version}}"
|
||||
}
|
||||
},
|
||||
"tasks": {
|
||||
"checking": "TaskMaster 설치 확인 중...",
|
||||
"notInstalled": {
|
||||
"title": "TaskMaster AI CLI가 설치되지 않았습니다",
|
||||
"description": "작업 관리 기능을 사용하려면 TaskMaster CLI가 필요합니다. 시작하려면 설치하세요:",
|
||||
"installCommand": "npm install -g task-master-ai",
|
||||
"viewOnGitHub": "GitHub에서 보기",
|
||||
"afterInstallation": "설치 후:",
|
||||
"steps": {
|
||||
"restart": "이 애플리케이션을 재시작하세요",
|
||||
"autoAvailable": "TaskMaster 기능이 자동으로 활성화됩니다",
|
||||
"initCommand": "프로젝트 디렉토리에서 task-master init을 사용하세요"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"enableLabel": "TaskMaster 통합 활성화",
|
||||
"enableDescription": "인터페이스 전체에 TaskMaster 작업, 배너 및 사이드바 표시"
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"authStatus": {
|
||||
"checking": "확인 중...",
|
||||
"connected": "연결됨",
|
||||
"notConnected": "연결되지 않음",
|
||||
"disconnected": "연결 끊김",
|
||||
"checkingAuth": "인증 상태 확인 중...",
|
||||
"loggedInAs": "{{email}}(으)로 로그인됨",
|
||||
"authenticatedUser": "인증된 사용자"
|
||||
},
|
||||
"account": {
|
||||
"claude": {
|
||||
"description": "Anthropic Claude AI 어시스턴트"
|
||||
},
|
||||
"cursor": {
|
||||
"description": "Cursor AI 기반 코드 에디터"
|
||||
},
|
||||
"codex": {
|
||||
"description": "OpenAI Codex AI 어시스턴트"
|
||||
}
|
||||
},
|
||||
"connectionStatus": "연결 상태",
|
||||
"login": {
|
||||
"title": "로그인",
|
||||
"reAuthenticate": "재인증",
|
||||
"description": "AI 기능을 활성화하려면 {{agent}} 계정에 로그인하세요",
|
||||
"reAuthDescription": "다른 계정으로 로그인하거나 자격 증명을 새로고침하세요",
|
||||
"button": "로그인",
|
||||
"reLoginButton": "재로그인"
|
||||
},
|
||||
"error": "오류: {{error}}"
|
||||
},
|
||||
"permissions": {
|
||||
"title": "권한 설정",
|
||||
"skipPermissions": {
|
||||
"label": "권한 확인 건너뛰기 (주의해서 사용)",
|
||||
"claudeDescription": "--dangerously-skip-permissions 플래그와 동일",
|
||||
"cursorDescription": "Cursor CLI의 -f 플래그와 동일"
|
||||
},
|
||||
"allowedTools": {
|
||||
"title": "허용된 도구",
|
||||
"description": "권한 확인 없이 자동으로 허용되는 도구",
|
||||
"placeholder": "예: \"Bash(git log:*)\" 또는 \"Write\"",
|
||||
"quickAdd": "자주 쓰는 도구 빠른 추가:",
|
||||
"empty": "설정된 허용 도구 없음"
|
||||
},
|
||||
"blockedTools": {
|
||||
"title": "차단된 도구",
|
||||
"description": "권한 확인 없이 자동으로 차단되는 도구",
|
||||
"placeholder": "예: \"Bash(rm:*)\"",
|
||||
"empty": "설정된 차단 도구 없음"
|
||||
},
|
||||
"allowedCommands": {
|
||||
"title": "허용된 Shell 명령어",
|
||||
"description": "권한 확인 없이 자동으로 허용되는 Shell 명령어",
|
||||
"placeholder": "예: \"Shell(ls)\" 또는 \"Shell(git status)\"",
|
||||
"quickAdd": "자주 쓰는 명령어 빠른 추가:",
|
||||
"empty": "설정된 허용 명령어 없음"
|
||||
},
|
||||
"blockedCommands": {
|
||||
"title": "차단된 Shell 명령어",
|
||||
"description": "자동으로 차단되는 Shell 명령어",
|
||||
"placeholder": "예: \"Shell(rm -rf)\" 또는 \"Shell(sudo)\"",
|
||||
"empty": "설정된 차단 명령어 없음"
|
||||
},
|
||||
"toolExamples": {
|
||||
"title": "도구 패턴 예시:",
|
||||
"bashGitLog": "- 모든 git log 명령어 허용",
|
||||
"bashGitDiff": "- 모든 git diff 명령어 허용",
|
||||
"write": "- 모든 Write 도구 사용 허용",
|
||||
"bashRm": "- 모든 rm 명령어 차단 (위험)"
|
||||
},
|
||||
"shellExamples": {
|
||||
"title": "Shell 명령어 예시:",
|
||||
"ls": "- ls 명령어 허용",
|
||||
"gitStatus": "- git status 허용",
|
||||
"npmInstall": "- npm install 허용",
|
||||
"rmRf": "- 재귀 삭제 차단"
|
||||
},
|
||||
"codex": {
|
||||
"permissionMode": "권한 모드",
|
||||
"description": "Codex가 파일 수정 및 명령어 실행을 처리하는 방식을 제어합니다",
|
||||
"modes": {
|
||||
"default": {
|
||||
"title": "기본",
|
||||
"description": "신뢰할 수 있는 명령어(ls, cat, grep, git status 등)만 자동 실행됩니다. 다른 명령어는 건너뜁니다. 워크스페이스에 쓰기 가능."
|
||||
},
|
||||
"acceptEdits": {
|
||||
"title": "편집 허용",
|
||||
"description": "워크스페이스 내에서 모든 명령어가 자동 실행됩니다. 샌드박스 내 완전 자동 모드."
|
||||
},
|
||||
"bypassPermissions": {
|
||||
"title": "권한 우회",
|
||||
"description": "제한 없는 전체 시스템 접근. 모든 명령어가 전체 디스크 및 네트워크 접근 권한으로 자동 실행됩니다. 주의해서 사용하세요."
|
||||
}
|
||||
},
|
||||
"technicalDetails": "기술 상세",
|
||||
"technicalInfo": {
|
||||
"default": "sandboxMode=workspace-write, approvalPolicy=untrusted. 신뢰할 수 있는 명령어: cat, cd, grep, head, ls, pwd, tail, git status/log/diff/show, find(-exec 제외) 등.",
|
||||
"acceptEdits": "sandboxMode=workspace-write, approvalPolicy=never. 프로젝트 디렉토리 내에서 모든 명령어 자동 실행.",
|
||||
"bypassPermissions": "sandboxMode=danger-full-access, approvalPolicy=never. 전체 시스템 접근, 신뢰할 수 있는 환경에서만 사용하세요.",
|
||||
"overrideNote": "채팅 인터페이스의 모드 버튼을 사용하여 세션별로 재정의할 수 있습니다."
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"add": "추가"
|
||||
}
|
||||
},
|
||||
"mcpServers": {
|
||||
"title": "MCP 서버",
|
||||
"description": {
|
||||
"claude": "Model Context Protocol 서버는 Claude에 추가 도구와 데이터 소스를 제공합니다",
|
||||
"cursor": "Model Context Protocol 서버는 Cursor에 추가 도구와 데이터 소스를 제공합니다",
|
||||
"codex": "Model Context Protocol 서버는 Codex에 추가 도구와 데이터 소스를 제공합니다"
|
||||
},
|
||||
"addButton": "MCP 서버 추가",
|
||||
"empty": "설정된 MCP 서버 없음",
|
||||
"serverType": "유형",
|
||||
"scope": {
|
||||
"local": "로컬",
|
||||
"user": "사용자"
|
||||
},
|
||||
"config": {
|
||||
"command": "명령어",
|
||||
"url": "URL",
|
||||
"args": "인수",
|
||||
"environment": "환경"
|
||||
},
|
||||
"tools": {
|
||||
"title": "도구",
|
||||
"count": "({{count}}):",
|
||||
"more": "+{{count}}개 더"
|
||||
},
|
||||
"actions": {
|
||||
"edit": "서버 편집",
|
||||
"delete": "서버 삭제"
|
||||
},
|
||||
"help": {
|
||||
"title": "Codex MCP 정보",
|
||||
"description": "Codex는 stdio 기반 MCP 서버를 지원합니다. 추가 도구와 리소스로 Codex의 기능을 확장하는 서버를 추가할 수 있습니다."
|
||||
}
|
||||
}
|
||||
}
|
||||
112
src/i18n/locales/ko/sidebar.json
Normal file
112
src/i18n/locales/ko/sidebar.json
Normal file
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"projects": {
|
||||
"title": "프로젝트",
|
||||
"newProject": "새 프로젝트",
|
||||
"deleteProject": "프로젝트 삭제",
|
||||
"renameProject": "프로젝트 이름 변경",
|
||||
"noProjects": "프로젝트가 없습니다",
|
||||
"loadingProjects": "프로젝트 로딩 중...",
|
||||
"searchPlaceholder": "프로젝트 검색...",
|
||||
"projectNamePlaceholder": "프로젝트 이름",
|
||||
"starred": "즐겨찾기",
|
||||
"all": "전체",
|
||||
"untitledSession": "제목 없는 세션",
|
||||
"newSession": "새 세션",
|
||||
"codexSession": "Codex 세션",
|
||||
"fetchingProjects": "Claude 프로젝트와 세션을 가져오는 중",
|
||||
"projects": "프로젝트",
|
||||
"noMatchingProjects": "일치하는 프로젝트 없음",
|
||||
"tryDifferentSearch": "검색어를 변경해보세요",
|
||||
"runClaudeCli": "프로젝트 디렉토리에서 Claude CLI를 실행하여 시작하세요"
|
||||
},
|
||||
"app": {
|
||||
"title": "Claude Code UI",
|
||||
"subtitle": "AI 코딩 어시스턴트 UI"
|
||||
},
|
||||
"sessions": {
|
||||
"title": "세션",
|
||||
"newSession": "새 세션",
|
||||
"deleteSession": "세션 삭제",
|
||||
"renameSession": "세션 이름 변경",
|
||||
"noSessions": "세션이 없습니다",
|
||||
"loadingSessions": "세션 로딩 중...",
|
||||
"unnamed": "이름 없음",
|
||||
"loading": "로딩 중...",
|
||||
"showMore": "더 많은 세션 보기"
|
||||
},
|
||||
"tooltips": {
|
||||
"viewEnvironments": "환경 보기",
|
||||
"hideSidebar": "사이드바 숨기기",
|
||||
"createProject": "새 프로젝트 생성",
|
||||
"refresh": "프로젝트 및 세션 새로고침 (Ctrl+R)",
|
||||
"renameProject": "프로젝트 이름 변경 (F2)",
|
||||
"deleteProject": "빈 프로젝트 삭제 (Delete)",
|
||||
"addToFavorites": "즐겨찾기에 추가",
|
||||
"removeFromFavorites": "즐겨찾기에서 제거",
|
||||
"editSessionName": "세션 이름 직접 편집",
|
||||
"deleteSession": "이 세션 영구 삭제",
|
||||
"save": "저장",
|
||||
"cancel": "취소"
|
||||
},
|
||||
"navigation": {
|
||||
"chat": "채팅",
|
||||
"files": "파일",
|
||||
"git": "Git",
|
||||
"terminal": "터미널",
|
||||
"tasks": "작업"
|
||||
},
|
||||
"actions": {
|
||||
"refresh": "새로고침",
|
||||
"settings": "설정",
|
||||
"collapseAll": "모두 접기",
|
||||
"expandAll": "모두 펼치기",
|
||||
"cancel": "취소",
|
||||
"save": "저장",
|
||||
"delete": "삭제",
|
||||
"rename": "이름 변경"
|
||||
},
|
||||
"status": {
|
||||
"active": "활성",
|
||||
"inactive": "비활성",
|
||||
"thinking": "생각 중...",
|
||||
"error": "오류",
|
||||
"aborted": "중단됨",
|
||||
"unknown": "알 수 없음"
|
||||
},
|
||||
"time": {
|
||||
"justNow": "방금 전",
|
||||
"oneMinuteAgo": "1분 전",
|
||||
"minutesAgo": "{{count}}분 전",
|
||||
"oneHourAgo": "1시간 전",
|
||||
"hoursAgo": "{{count}}시간 전",
|
||||
"oneDayAgo": "1일 전",
|
||||
"daysAgo": "{{count}}일 전"
|
||||
},
|
||||
"messages": {
|
||||
"deleteConfirm": "정말 삭제하시겠습니까?",
|
||||
"renameSuccess": "이름이 변경되었습니다",
|
||||
"deleteSuccess": "삭제되었습니다",
|
||||
"errorOccurred": "오류가 발생했습니다",
|
||||
"deleteSessionConfirm": "이 세션을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.",
|
||||
"deleteProjectConfirm": "이 빈 프로젝트를 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.",
|
||||
"enterProjectPath": "프로젝트 경로를 입력해주세요",
|
||||
"deleteSessionFailed": "세션 삭제 실패. 다시 시도해주세요.",
|
||||
"deleteSessionError": "세션 삭제 오류. 다시 시도해주세요.",
|
||||
"deleteProjectFailed": "프로젝트 삭제 실패. 다시 시도해주세요.",
|
||||
"deleteProjectError": "프로젝트 삭제 오류. 다시 시도해주세요.",
|
||||
"createProjectFailed": "프로젝트 생성 실패. 다시 시도해주세요.",
|
||||
"createProjectError": "프로젝트 생성 오류. 다시 시도해주세요."
|
||||
},
|
||||
"version": {
|
||||
"updateAvailable": "업데이트 가능"
|
||||
},
|
||||
"deleteConfirmation": {
|
||||
"deleteProject": "프로젝트 삭제",
|
||||
"deleteSession": "세션 삭제",
|
||||
"confirmDelete": "정말 삭제하시겠습니까",
|
||||
"sessionCount_one": "이 프로젝트에는 {{count}}개의 대화가 있습니다.",
|
||||
"sessionCount_other": "이 프로젝트에는 {{count}}개의 대화가 있습니다.",
|
||||
"allConversationsDeleted": "모든 대화가 영구적으로 삭제됩니다.",
|
||||
"cannotUndo": "이 작업은 취소할 수 없습니다."
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user