var i18n = { ko: { eyebrow: "튜터 플랫폼", loginHeading: "답변을 증거로", loginDesc: "짧은 연습 루프로 면접 준비도를 눈으로 확인하세요.", titleWorkspace: "면접 연습", subtitleWorkspace: "백엔드 면접 연습을 시작하고, 하나의 답변을 증거로 만드세요.", startSession: "진단 세션 시작", startHint: "면접 질문을 생성하고 첫 답변을 만들어보세요.", userId: "사용자 ID", targetRole: "목표 직무", stack: "기술 스택", timeline: "준비 기간", startDiagnostic: "진단 시작", signOut: "로그아웃", questions: "질문 목록", yourAnswer: "내 답변", answerHint: "구체적인 프로덕션 관점에서 답변하세요.", noActiveSession: "활성 세션 없음", emptyQuestions: "면접 질문을 불러오려면 진단 세션을 시작하세요.", answerLabel: "답변", answerPlaceholder: "질문을 선택한 후, 구체적인 프로덕션 관점에서 답변하세요.", submitAnswer: "답변 제출", contentEyebrow: "콘텐츠 작업", contentTitle: "소스 → 에셋 프롬프트", materialTitle: "자료 제목", sourceType: "소스 유형", sourceMaterial: "소스 자료", ingestMaterial: "자료 수집", emptyOntology: "자료를 수집하면 개념 후보를 확인할 수 있습니다.", concept: "개념", assetType: "에셋 유형", generatePrompt: "프롬프트 생성", emptyAsset: "프롬프트를 생성하면 모델 키, 검토 상태, 근거를 확인할 수 있습니다.", feedbackEyebrow: "피드백", rubricResult: "채점 결과", feedbackEmpty: "답변을 제출하면 채점 결과가 여기에 표시됩니다.", emptyFeedback: "답변을 제출하면 등급, 근거, 후속 질문을 확인할 수 있습니다.", progressEyebrow: "진행 상황", learningState: "학습 상태", emptyProgress: "답변을 제출하면 학습자 메모리와 준비도가 업데이트됩니다.", refresh: "새로고침", ready: "준비 완료", creatingSession: "진단 세션 생성 중…", sessionReady: function(id) { return "세션 " + id + " 준비 완료"; }, submittingAnswer: "답변 제출 중…", answerGraded: function(grade) { return "답변 등급: " + grade; }, answerGradedLabel: "채점 완료", answerQuestion: "답변 작성", selectQuestion: "질문 선택", reviewComplete: "복습 완료", ingestingMaterial: "자료 수집 중…", materialIngested: function(id) { return "자료 " + id + " 수집 완료"; }, generatingPrompt: "프롬프트 생성 중…", promptGenerated: function(id) { return "프롬프트 " + id + " 생성 완료"; }, refreshingProgress: "학습 진행 상황 새로고침 중…", progressUpdated: "학습 진행 상황 업데이트 완료", selected: function(id) { return id + " 선택됨"; }, contentReady: "콘텐츠 작업 공간 준비 완료", sessionReadyShort: "세션 준비 완료", signedInAs: function(email) { return email + "님으로 로그인됨"; }, signedOut: "로그아웃됨", followUp: "후속 질문", evidence: "근거", gaps: "부족한 점", conceptMemory: "개념 메모리", nextChallenge: "다음 도전", readiness: "준비도", modelKey: "모델 키", reviewState: "검토 상태", verifyModelId: "모델 ID 확인 필요", yes: "예", no: "아니오", questionId: "질문 ID", starting: "시작 중…", grading: "채점 중…", ingesting: "수집 중…", generating: "생성 중…", questionsSuffix: "개 질문", conceptsSuffix: "개 개념", edgesSuffix: "개 엣지", gapsSuffix: "개 갭", candidateConcepts: "후보 개념", noCandidates: "아직 후보가 없습니다.", answerWasGraded: "답변이 채점되었습니다.", }, en: { eyebrow: "Tutor Platform", loginHeading: "Turn answers into evidence", loginDesc: "Visualize your interview readiness through short practice loops.", titleWorkspace: "Interview practice", subtitleWorkspace: "Start a focused backend interview loop and turn one answer into evidence.", startSession: "Start diagnostic session", startHint: "Generate interview questions and write your first answer.", userId: "User ID", targetRole: "Target role", stack: "Stack", timeline: "Timeline", startDiagnostic: "Start diagnostic", signOut: "Sign out", questions: "Questions", yourAnswer: "Your answer", answerHint: "Answer with concrete production reasoning.", noActiveSession: "No active session", emptyQuestions: "Start a diagnostic session to load interview questions.", answerLabel: "Answer", answerPlaceholder: "Select a question, then answer with concrete production reasoning.", submitAnswer: "Submit answer", contentEyebrow: "Content operations", contentTitle: "Source to asset prompt", materialTitle: "Material title", sourceType: "Source type", sourceMaterial: "Source material", ingestMaterial: "Ingest material", emptyOntology: "Ingest material to inspect ontology candidates.", concept: "Concept", assetType: "Asset type", generatePrompt: "Generate prompt", emptyAsset: "Generate a prompt to inspect model key, review state, and evidence.", feedbackEyebrow: "Feedback", rubricResult: "Rubric result", feedbackEmpty: "Submit an answer to see your grade and feedback here.", emptyFeedback: "Submit an answer to see grade, evidence, and follow-up.", progressEyebrow: "Progress", learningState: "Learning state", emptyProgress: "Answer once to update learner memory and readiness.", refresh: "Refresh", ready: "Ready", creatingSession: "Creating diagnostic session…", sessionReady: function(id) { return "Session " + id + " ready"; }, submittingAnswer: "Submitting answer…", answerGraded: function(grade) { return "Answer graded as " + grade; }, answerGradedLabel: "Graded", answerQuestion: "Answer", selectQuestion: "Select", reviewComplete: "Review done", ingestingMaterial: "Ingesting material…", materialIngested: function(id) { return "Material " + id + " ingested"; }, generatingPrompt: "Generating prompt candidate…", promptGenerated: function(id) { return "Prompt " + id + " generated"; }, refreshingProgress: "Refreshing learning progress…", progressUpdated: "Learning progress updated", selected: function(id) { return "Selected " + id; }, contentReady: "Content workspace ready", sessionReadyShort: "Session ready", signedInAs: function(email) { return "Signed in as " + email; }, signedOut: "Signed out", followUp: "Follow-up", evidence: "Evidence", gaps: "Gaps", conceptMemory: "Concept memory", nextChallenge: "Next challenge", readiness: "readiness", modelKey: "Model key", reviewState: "Review state", verifyModelId: "verify model id", yes: "yes", no: "no", questionId: "question id", starting: "Starting…", grading: "Grading…", ingesting: "Ingesting…", generating: "Generating…", questionsSuffix: "questions", conceptsSuffix: "concepts", edgesSuffix: "edges", gapsSuffix: "gaps", candidateConcepts: "Candidate concepts", noCandidates: "No candidates yet.", answerWasGraded: "Answer was graded.", }, }; window.t = function (key) { var args = Array.prototype.slice.call(arguments, 1); var lang = localStorage.getItem("tutor_lang") || document.documentElement.lang || "ko"; var text = i18n[lang]?.[key] ?? i18n["en"]?.[key] ?? key; return typeof text === "function" ? text.apply(null, args) : text; } var questionTexts = { ko: { "backend-http-idempotency": "HTTP 메서드가 멱등성을 가지려면 어떤 조건이 필요하며, 재시도 시 왜 중요한가요?", "backend-db-index-tradeoff": "데이터베이스 인덱스를 추가하면 API가 어떻게 개선되며, 어떤 트레이드오프가 발생할 수 있나요?", "backend-cache-invalidation": "API 응답을 캐싱할지 어떻게 결정하며, 오래된 데이터는 어떻게 처리하나요?", }, en: { "backend-http-idempotency": "What makes an HTTP method idempotent, and why does that matter for retries?", "backend-db-index-tradeoff": "When would adding a database index improve an API, and what tradeoffs can it introduce?", "backend-cache-invalidation": "How would you decide whether to cache an API response, and how would you handle stale data?", }, }; window.tq = function (id) { var lang = localStorage.getItem("tutor_lang") || document.documentElement.lang || "ko"; return questionTexts[lang]?.[id] ?? questionTexts["en"]?.[id] ?? ""; }; window.updateStaticText = function () { var lang = localStorage.getItem("tutor_lang") || document.documentElement.lang || "ko"; document.documentElement.lang = lang; document.querySelectorAll("[data-i18n]").forEach(function(el) { var k = el.dataset.i18n; var v = i18n[lang]?.[k] ?? i18n["en"]?.[k] ?? ""; var text = typeof v === "function" ? v() : v; if (el.classList.contains("login-divider")) { el.setAttribute("data-label", text); } else if (el.tagName === "INPUT" || el.tagName === "TEXTAREA") { if (el.placeholder !== undefined) el.placeholder = text; } else if (text.indexOf("<") >= 0) { el.innerHTML = text; } else { el.textContent = text; } }); document.querySelectorAll("[data-i18n-placeholder]").forEach(function(el) { var k = el.dataset.i18nPlaceholder; var v = i18n[lang]?.[k] ?? i18n["en"]?.[k] ?? ""; var text = typeof v === "function" ? v() : v; el.placeholder = text; }); }