Spaces:
Sleeping
Sleeping
| export type Language = "vi" | "en"; | |
| const languageStorageKey = "carepath-demo-language"; | |
| export const copy = { | |
| vi: { | |
| title: "CarePath | Phiên dịch khám bệnh trực tiếp", | |
| breadcrumb: "Đường dẫn sản phẩm", | |
| status: "Bản mô phỏng tương tác", | |
| allProducts: "Tất cả chức năng", | |
| language: "Ngôn ngữ thanh sản phẩm", | |
| productName: "Phiên dịch khám bệnh trực tiếp", | |
| consent: { | |
| eyebrow: "Phiên dịch khám bệnh trực tiếp", | |
| heading: "Phiên dịch khám bệnh trực tiếp", | |
| description: "Dịch hai chiều giữa bác sĩ tiếng Việt và bệnh nhân tiếng Anh trong lúc khám.", | |
| steps: "Cách phiên dịch diễn ra", | |
| doctorSpeaks: "Bác sĩ nói tiếng Việt", | |
| aiToPatient: "AI dịch sang tiếng Anh cho bệnh nhân", | |
| patientSpeaks: "Bệnh nhân trả lời bằng tiếng Anh", | |
| aiToDoctor: "AI dịch lại sang tiếng Việt cho bác sĩ", | |
| limitation: "CarePath chỉ hỗ trợ phiên dịch, không đưa ra chẩn đoán hoặc tư vấn điều trị.", | |
| acknowledgements: "Xác nhận trước khi bắt đầu", | |
| aiDisclosure: | |
| "Tôi đã được giải thích rằng bản dịch do AI tạo ra có thể có lỗi và cần được bác sĩ kiểm tra trước khi sử dụng.", | |
| interpreterRight: | |
| "Tôi đã được giải thích rằng có thể yêu cầu phiên dịch viên trực tiếp bất cứ lúc nào.", | |
| start: "Bắt đầu phiên dịch", | |
| starting: "Đang bắt đầu…", | |
| retry: "Thử lại để bắt đầu phiên dịch", | |
| startError: "Không thể bắt đầu phiên dịch. Vui lòng kiểm tra kết nối máy chủ và thử lại.", | |
| startHint: "Đánh dấu cả hai xác nhận để bắt đầu.", | |
| startReadyHint: "Đã đủ xác nhận. Bạn có thể bắt đầu phiên dịch.", | |
| }, | |
| deviceCheck: { | |
| title: "Kiểm tra micrô trước khi bắt đầu", | |
| body: "Kiểm tra micrô để dùng chế độ nói, hoặc tiếp tục bằng văn bản.", | |
| microphone: "Micrô", | |
| test: "Kiểm tra micrô", | |
| retry: "Thử lại", | |
| idle: "Chưa kiểm tra micrô.", | |
| ready: "Micrô đã sẵn sàng.", | |
| level: "Mức âm thanh", | |
| scaleLow: "Nhỏ", | |
| scaleHigh: "To", | |
| continueVoice: "Tiếp tục bằng micrô", | |
| continueTyped: "Tiếp tục bằng văn bản", | |
| unavailable: "Không tìm thấy micrô. Bạn có thể thử lại hoặc tiếp tục bằng văn bản.", | |
| denied: "Không thể dùng micrô. Hãy cấp quyền rồi thử lại, hoặc tiếp tục bằng văn bản.", | |
| }, | |
| workspace: { | |
| title: "Phiên dịch khám bệnh trực tiếp", | |
| mockDisclaimer: "Bản mô phỏng này không dùng cho chăm sóc lâm sàng thực tế.", | |
| requestInterpreter: "Yêu cầu phiên dịch viên trực tiếp", | |
| escalationTitle: "Đã yêu cầu phiên dịch viên trực tiếp", | |
| escalationBody: "Tạm dừng phát bản dịch AI và kết nối phiên dịch viên đủ điều kiện trước khi tiếp tục.", | |
| controls: "Điều khiển nói", | |
| holdToTalk: "Nhấn giữ để nói", | |
| doctor: "Bác sĩ", | |
| patient: "Bệnh nhân", | |
| vietnamese: "Tiếng Việt", | |
| english: "Tiếng Anh", | |
| speaker: "Người nói", | |
| regionInactiveHint: "Chọn khu vực này để nói hoặc nhập cho người này.", | |
| typedFallback: "Nhập văn bản thay thế", | |
| typedPlaceholder: "Nhập nội dung cần dịch", | |
| send: "Gửi", | |
| connecting: "Đang kết nối", | |
| connected: "Đã kết nối", | |
| disconnected: "Đã ngắt kết nối", | |
| inputReady: "Sẵn sàng", | |
| inputProcessing: "Đang xử lý", | |
| inputDelivered: "Đã chuyển bản dịch", | |
| inputReviewRequired: "Cần bác sĩ xác nhận", | |
| recording: "Đang ghi lời nói của {speaker}", | |
| connectionNotReady: "Kết nối chưa sẵn sàng.", | |
| connectionNotReadyType: "Kết nối chưa sẵn sàng. Hãy nhập văn bản thay thế.", | |
| microphoneUnavailable: "Không thể dùng micrô. Hãy nhập văn bản thay thế.", | |
| microphoneDenied: "Micrô chưa được cấp quyền. Hãy nhập văn bản thay thế.", | |
| lowConfidence: "Độ tin cậy thấp. Hãy nói lại hoặc nhập văn bản.", | |
| repeatTurn: "Nói lại", | |
| typeTurn: "Nhập văn bản", | |
| confirmationRequired: "Cần bác sĩ xác nhận trước khi phát cho bệnh nhân.", | |
| confirmFailed: "Không thể xác nhận lượt dịch.", | |
| escalationFailed: "Không thể đánh dấu đã yêu cầu phiên dịch viên.", | |
| playbackSuppressed: "Đã tạm dừng phát tự động. Chỉ tiếp tục sau khi bác sĩ xác nhận phát cục bộ.", | |
| resumePlayback: "Tiếp tục phát tự động trên thiết bị này", | |
| turnError: "Lượt dịch gặp lỗi. Hãy thử lại hoặc nhập văn bản.", | |
| pipelineFailureTitle: "Lượt dịch đã được chặn vì xử lý thất bại", | |
| sourceUnavailable: "Chưa thể tạo văn bản nguồn từ âm thanh.", | |
| translationUnavailable: "Chưa có bản dịch để phát cho người bệnh.", | |
| pipelineFailureAction: "Kiểm tra nội dung nguồn nếu có, thử lại hoặc yêu cầu phiên dịch viên trực tiếp.", | |
| lifecycle: "Kết thúc phiên", | |
| endSession: "Kết thúc phiên", | |
| withdrawConsent: "Rút lại xác nhận", | |
| deleteSession: "Xóa dữ liệu phiên", | |
| deleteConfirm: "Xóa toàn bộ dữ liệu của phiên này?", | |
| lifecycleFailed: "Không thể hoàn tất thao tác. Phiên vẫn được giữ ở trạng thái an toàn.", | |
| retry: "Thử lại", | |
| confirmations: "Xác nhận của bác sĩ", | |
| confirmationRequiredLabel: "Cần bác sĩ xác nhận", | |
| interpreterRecommended: "Khuyến nghị phiên dịch viên trực tiếp", | |
| readback: "Đọc lại để xác nhận", | |
| entity: "Thông tin", | |
| source: "Bản gốc", | |
| translation: "Bản dịch", | |
| flags: "Lưu ý", | |
| editTranslation: "Sửa bản dịch", | |
| confirm: "Xác nhận", | |
| saveEdit: "Lưu chỉnh sửa", | |
| escalate: "Yêu cầu phiên dịch viên", | |
| transcript: "Nội dung trao đổi", | |
| turns: "lượt", | |
| noTurns: "Chưa có lượt trao đổi.", | |
| sourceLanguage: "Ngôn ngữ gốc", | |
| targetLanguage: "Ngôn ngữ dịch", | |
| blocked: "Đã chặn, chờ bác sĩ xác nhận.", | |
| patientSafeMask: "Nội dung đang chờ bác sĩ xem xét.", | |
| openReview: "Mở bản xem xét", | |
| reviewOpened: "Đã mở bản xem xét dành cho bác sĩ.", | |
| draftTranslation: "Bản dịch nháp", | |
| riskReason: "Lý do cần xem xét", | |
| criticalEntities: "Thông tin cần kiểm tra", | |
| confirmAndPlay: "Xác nhận và phát", | |
| saveEditAndPlay: "Lưu chỉnh sửa và phát", | |
| editRequired: "Bản dịch chỉnh sửa không được để trống.", | |
| riskSpans: "Thông tin cần kiểm tra", | |
| feedback: "Báo lỗi bản dịch", | |
| feedbackSaved: "Đã lưu phản hồi.", | |
| reason: "Lý do", | |
| comment: "Ghi chú", | |
| submitFeedback: "Gửi phản hồi", | |
| risk: { low: "Thấp", medium: "Trung bình", high: "Cao", critical: "Nghiêm trọng", other: "Cần kiểm tra" }, | |
| status: { delivered: "Đã chuyển", awaiting_confirm: "Chờ xác nhận", confirmed: "Đã xác nhận", blocked: "Đã chặn", other: "Đang xử lý" }, | |
| feedbackReason: { wrong_term: "Sai thuật ngữ", wrong_meaning: "Sai nghĩa", missing: "Thiếu nội dung", other: "Khác" }, | |
| riskKind: { dose_number: "Liều lượng", dose: "Liều lượng", other: "Thông tin cần kiểm tra" }, | |
| }, | |
| demo: { | |
| eyebrow: "Mô phỏng trước khi xác nhận", | |
| heading: "Xem cách phiên dịch được xử lý", | |
| start: "Xem mô phỏng", | |
| next: "Xem tình huống tiếp theo", | |
| restart: "Xem lại mô phỏng", | |
| step: "Tình huống {current}/3", | |
| normal: "Bản dịch được chuyển", | |
| lowConfidence: "Độ tin cậy thấp", | |
| blocked: "Đã chặn, chờ bác sĩ xác nhận", | |
| normalSource: "Tôi bị đau đầu từ sáng nay.", | |
| normalTranslation: "I have had a headache since this morning.", | |
| lowSource: "Tôi uống một viên... hay nửa viên?", | |
| lowTranslation: "I took one tablet... or half a tablet?", | |
| blockedSource: "Uống 500 mg mỗi ngày.", | |
| blockedTranslation: "Take 500 mg every day.", | |
| }, | |
| intent: { | |
| moment: "Trong buổi khám", | |
| roleQuestion: "Hôm nay bạn là ai?", | |
| doctor: "Bác sĩ", | |
| clinicStaff: "Nhân viên phòng khám", | |
| directionQuestion: "Bạn cần dịch theo chiều nào?", | |
| viToEn: "Tiếng Việt → Tiếng Anh", | |
| enToVi: "Tiếng Anh → Tiếng Việt", | |
| continue: "Tiếp tục", | |
| skip: "Bỏ qua và dùng lựa chọn đề xuất", | |
| recommended: "Đề xuất", | |
| }, | |
| stepper: { | |
| label: "Tiến trình bắt đầu phiên dịch", | |
| language: "Ngôn ngữ", | |
| about: "Về bạn", | |
| consent: "Xác nhận", | |
| device: "Kiểm tra thiết bị", | |
| start: "Bắt đầu", | |
| complete: "Đã hoàn thành", | |
| current: "Đang thực hiện", | |
| upcoming: "Tiếp theo", | |
| }, | |
| checklist: { title: "Danh sách an toàn phiên đầu", delivered: "Đã chuyển lượt đầu tiên", confirmed: "Đã hoàn tất xác nhận", escalation: "Đã xác định nút yêu cầu phiên dịch viên", dismiss: "Ẩn danh sách" }, | |
| }, | |
| en: { | |
| title: "CarePath | Medical Interpreter", | |
| breadcrumb: "Product breadcrumb", | |
| status: "Interactive mock simulation", | |
| allProducts: "All products", | |
| language: "Product bar language", | |
| productName: "Medical Interpreter", | |
| consent: { | |
| eyebrow: "Medical Interpreter", | |
| heading: "Live medical interpretation", | |
| description: "Two-way interpretation between a Vietnamese-speaking clinician and an English-speaking patient during a visit.", | |
| steps: "How interpretation works", | |
| doctorSpeaks: "The clinician speaks Vietnamese", | |
| aiToPatient: "AI translates to English for the patient", | |
| patientSpeaks: "The patient replies in English", | |
| aiToDoctor: "AI translates back to Vietnamese for the clinician", | |
| limitation: "CarePath provides translation support only; it does not provide diagnoses or treatment advice.", | |
| acknowledgements: "Confirm before starting", | |
| aiDisclosure: | |
| "I have been told that AI-generated translations can contain errors and must be reviewed by the clinician before use.", | |
| interpreterRight: | |
| "I have been told that a human interpreter can be requested at any time.", | |
| start: "Start interpreting", | |
| starting: "Starting…", | |
| retry: "Try starting interpretation again", | |
| startError: "Unable to start interpretation. Check the server connection and try again.", | |
| startHint: "Check both confirmations to start.", | |
| startReadyHint: "Both confirmations complete. You can start interpreting.", | |
| }, | |
| deviceCheck: { | |
| title: "Check the microphone before starting", | |
| body: "Test a microphone for voice mode, or continue with typed turns.", | |
| microphone: "Microphone", | |
| test: "Test microphone", | |
| retry: "Try again", | |
| idle: "Microphone not tested yet.", | |
| ready: "Microphone is ready.", | |
| level: "Sound level", | |
| scaleLow: "Quiet", | |
| scaleHigh: "Loud", | |
| continueVoice: "Continue with microphone", | |
| continueTyped: "Continue with typed turns", | |
| unavailable: "No microphone was found. Try again or continue with typed turns.", | |
| denied: "The microphone is unavailable. Grant permission and try again, or continue with typed turns.", | |
| }, | |
| workspace: { | |
| title: "Live medical interpretation", | |
| mockDisclaimer: "This simulation is not for real clinical care.", | |
| requestInterpreter: "Request a human interpreter", | |
| escalationTitle: "Human interpreter requested", | |
| escalationBody: "Pause AI playback and connect a qualified interpreter before continuing.", | |
| controls: "Speaking controls", | |
| holdToTalk: "Hold to talk", | |
| doctor: "Clinician", | |
| patient: "Patient", | |
| vietnamese: "Vietnamese", | |
| english: "English", | |
| speaker: "Speaker", | |
| regionInactiveHint: "Select this area to speak or type for this person.", | |
| typedFallback: "Typed fallback", | |
| typedPlaceholder: "Type a turn to interpret", | |
| send: "Send", | |
| connecting: "Connecting", | |
| connected: "Connected", | |
| disconnected: "Disconnected", | |
| inputReady: "Ready", | |
| inputProcessing: "Processing", | |
| inputDelivered: "Translation delivered", | |
| inputReviewRequired: "Clinician review required", | |
| recording: "Recording {speaker}", | |
| connectionNotReady: "Connection is not ready.", | |
| connectionNotReadyType: "Connection is not ready. Type the turn instead.", | |
| microphoneUnavailable: "Microphone is unavailable. Type the turn instead.", | |
| microphoneDenied: "Microphone permission denied. Type the turn instead.", | |
| lowConfidence: "Low confidence. Please repeat or type the turn.", | |
| repeatTurn: "Repeat", | |
| typeTurn: "Type text", | |
| confirmationRequired: "Clinician confirmation is required before patient playback.", | |
| confirmFailed: "Could not confirm the turn.", | |
| escalationFailed: "Could not mark the session escalated.", | |
| playbackSuppressed: "Automatic playback is paused. Resume only after the clinician confirms local playback.", | |
| resumePlayback: "Resume automatic playback on this device", | |
| turnError: "The turn could not be processed. Please try again or type it.", | |
| pipelineFailureTitle: "Turn blocked because processing failed", | |
| sourceUnavailable: "No source text could be produced from the audio.", | |
| translationUnavailable: "No translation is available for patient playback.", | |
| pipelineFailureAction: "Check the source when available, retry, or request a human interpreter.", | |
| lifecycle: "Session actions", | |
| endSession: "End session", | |
| withdrawConsent: "Withdraw consent", | |
| deleteSession: "Delete session data", | |
| deleteConfirm: "Delete all data for this session?", | |
| lifecycleFailed: "The action could not be completed. The session remains safely stopped.", | |
| retry: "Retry", | |
| confirmations: "Clinician confirmation", | |
| confirmationRequiredLabel: "Clinician confirmation required", | |
| interpreterRecommended: "Human interpreter recommended", | |
| readback: "Read-back", | |
| entity: "Item", | |
| source: "Source", | |
| translation: "Translation", | |
| flags: "Notes", | |
| editTranslation: "Edit translation", | |
| confirm: "Confirm", | |
| saveEdit: "Save edit", | |
| escalate: "Request interpreter", | |
| transcript: "Conversation", | |
| turns: "turns", | |
| noTurns: "No turns yet.", | |
| sourceLanguage: "Source language", | |
| targetLanguage: "Translation language", | |
| blocked: "Blocked pending clinician confirmation.", | |
| patientSafeMask: "This content is awaiting clinician review.", | |
| openReview: "Open review", | |
| reviewOpened: "Clinician review opened.", | |
| draftTranslation: "Draft translation", | |
| riskReason: "Reason for review", | |
| criticalEntities: "Critical information to check", | |
| confirmAndPlay: "Confirm and play", | |
| saveEditAndPlay: "Save edit and play", | |
| editRequired: "An edited translation cannot be empty.", | |
| riskSpans: "Items to check", | |
| feedback: "Flag translation", | |
| feedbackSaved: "Feedback saved.", | |
| reason: "Reason", | |
| comment: "Comment", | |
| submitFeedback: "Submit feedback", | |
| risk: { low: "Low", medium: "Medium", high: "High", critical: "Critical", other: "Needs review" }, | |
| status: { delivered: "Delivered", awaiting_confirm: "Awaiting confirmation", confirmed: "Confirmed", blocked: "Blocked", other: "Processing" }, | |
| feedbackReason: { wrong_term: "Wrong term", wrong_meaning: "Wrong meaning", missing: "Missing content", other: "Other" }, | |
| riskKind: { dose_number: "Dose", dose: "Dose", other: "Item to check" }, | |
| }, | |
| demo: { | |
| eyebrow: "Pre-consent simulation", | |
| heading: "See how interpretation is handled", | |
| start: "View simulation", | |
| next: "View next situation", | |
| restart: "Replay simulation", | |
| step: "Situation {current}/3", | |
| normal: "Translation delivered", | |
| lowConfidence: "Low confidence", | |
| blocked: "Blocked pending clinician confirmation", | |
| normalSource: "I have had a headache since this morning.", | |
| normalTranslation: "Tôi bị đau đầu từ sáng nay.", | |
| lowSource: "I took one tablet... or half a tablet?", | |
| lowTranslation: "Tôi uống một viên... hay nửa viên?", | |
| blockedSource: "Take 500 mg every day.", | |
| blockedTranslation: "Uống 500 mg mỗi ngày.", | |
| }, | |
| intent: { | |
| moment: "During the visit", | |
| roleQuestion: "Who are you today?", | |
| doctor: "Clinician", | |
| clinicStaff: "Clinic staff", | |
| directionQuestion: "Which direction do you need?", | |
| viToEn: "Vietnamese → English", | |
| enToVi: "English → Vietnamese", | |
| continue: "Continue", | |
| skip: "Skip and use recommended choices", | |
| recommended: "Recommended", | |
| }, | |
| stepper: { | |
| label: "Interpreter setup progress", | |
| language: "Language", | |
| about: "About you", | |
| consent: "Confirmation", | |
| device: "Device check", | |
| start: "Start", | |
| complete: "Complete", | |
| current: "Current step", | |
| upcoming: "Upcoming", | |
| }, | |
| checklist: { title: "First-session safety checklist", delivered: "First turn delivered", confirmed: "Confirmation completed", escalation: "Human-interpreter control located", dismiss: "Dismiss checklist" }, | |
| }, | |
| } as const; | |
| export function initialLanguage(): Language { | |
| const value = new URLSearchParams(window.location.search).get("lang"); | |
| if (value !== null) { | |
| return value === "en" || value === "vi" ? value : "vi"; | |
| } | |
| return localStorage.getItem(languageStorageKey) === "en" ? "en" : "vi"; | |
| } | |
| export function persistLanguage(language: Language) { | |
| localStorage.setItem(languageStorageKey, language); | |
| } | |