Files

244 lines
10 KiB
JavaScript
Raw Permalink Normal View History

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: "채점 중…",
uploadFile: "파일 업로드",
uploadAndIngest: "업로드 및 수집",
pasteTextToggle: "또는 텍스트 붙여넣기",
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…",
uploadFile: "Upload file",
uploadAndIngest: "Upload & ingest",
pasteTextToggle: "Or paste text",
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;
});
}