From ba2bc4e69291ffff63272a5e4e2d29b3aa623502 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 10 Aug 2026 03:54:44 +0000 Subject: [PATCH] feat(i18n): add Vietnamese locale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `vi` as a thirteenth locale: 231 UI strings, all nine organs, and all thirty-six hotspots. Vietnamese gets its own `ScriptGroup` rather than reusing `latin`, because DM Sans ships no Vietnamese subset — the tone marks fall back to a system face mid-paragraph. The sans face becomes Be Vietnam Pro, drawn for these diacritics so the marks clear the ascenders; Cormorant Garamond stays, with its `vietnamese` subset requested. Only `vi` loads that pair, so the twelve existing locales pay nothing. Terminology follows Vietnamese medical usage (tâm nhĩ / tâm thất, van hai lá, tá tràng, hỗng tràng, biểu bì / trung bì / hạ bì). Numbers follow Vietnamese convention — comma for decimals, period for thousands: `1,3–1,4 kg`, `100.000 lần`. `npm run i18n:audit` passes with no errors. --- app/i18n/config.ts | 3 +- app/i18n/dictionaries.ts | 2 + app/i18n/fonts.ts | 11 ++ app/i18n/organs/vi.ts | 210 +++++++++++++++++++++++++++++++++++++++ app/i18n/ui/vi.ts | 70 +++++++++++++ 5 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 app/i18n/organs/vi.ts create mode 100644 app/i18n/ui/vi.ts diff --git a/app/i18n/config.ts b/app/i18n/config.ts index f09ca6f..dae7269 100644 --- a/app/i18n/config.ts +++ b/app/i18n/config.ts @@ -1,6 +1,6 @@ /** Script group decides which font pair loads. Keeping this separate from the * locale list means adding a Latin-script locale costs no extra font weight. */ -export type ScriptGroup = "latin" | "cyrillic" | "devanagari" | "arabic" | "sc" | "jp" | "kr"; +export type ScriptGroup = "latin" | "vietnamese" | "cyrillic" | "devanagari" | "arabic" | "sc" | "jp" | "kr"; export type LocaleConfig = { code: string; @@ -27,6 +27,7 @@ export const locales: LocaleConfig[] = [ { code: "ru", nativeName: "Русский", englishName: "Russian", country: "Russia", dir: "ltr", script: "cyrillic", intl: "ru_RU" }, { code: "id", nativeName: "Indonesia", englishName: "Indonesian", country: "Indonesia", dir: "ltr", script: "latin", intl: "id_ID" }, { code: "ko", nativeName: "한국어", englishName: "Korean", country: "South Korea", dir: "ltr", script: "kr", intl: "ko_KR" }, + { code: "vi", nativeName: "Tiếng Việt", englishName: "Vietnamese", country: "Vietnam", dir: "ltr", script: "vietnamese", intl: "vi_VN" }, ]; export const defaultLocale = "en"; diff --git a/app/i18n/dictionaries.ts b/app/i18n/dictionaries.ts index e46ab30..55e0abe 100644 --- a/app/i18n/dictionaries.ts +++ b/app/i18n/dictionaries.ts @@ -16,6 +16,7 @@ const uiLoaders: Record Promise> = { ru: () => import("./ui/ru").then((m) => m.ui), id: () => import("./ui/id").then((m) => m.ui), ko: () => import("./ui/ko").then((m) => m.ui), + vi: () => import("./ui/vi").then((m) => m.ui), }; const organLoaders: Record Promise> = { @@ -31,6 +32,7 @@ const organLoaders: Record Promise> = { ru: () => import("./organs/ru").then((m) => m.organs), id: () => import("./organs/id").then((m) => m.organs), ko: () => import("./organs/ko").then((m) => m.organs), + vi: () => import("./organs/vi").then((m) => m.organs), }; export async function getDictionary(locale: string): Promise { diff --git a/app/i18n/fonts.ts b/app/i18n/fonts.ts index 7b811a1..aaed90d 100644 --- a/app/i18n/fonts.ts +++ b/app/i18n/fonts.ts @@ -1,4 +1,5 @@ import { + Be_Vietnam_Pro, Cormorant_Garamond, DM_Sans, Noto_Naskh_Arabic, @@ -16,6 +17,15 @@ const cormorantCyrillic = Cormorant_Garamond({ variable: "--font-serif", subsets const dmSans = DM_Sans({ variable: "--font-sans", subsets: ["latin", "latin-ext"] }); const notoSansCyrillic = Noto_Sans({ variable: "--font-sans", subsets: ["cyrillic", "latin"] }); +// Vietnamese needs Latin Extended plus the precomposed tone marks Google ships +// in the dedicated `vietnamese` subset. Requesting it only for `vi` keeps the +// other Latin locales from paying for glyphs they never render. +const cormorantVietnamese = Cormorant_Garamond({ variable: "--font-serif", subsets: ["latin", "latin-ext", "vietnamese"], weight: ["400", "500", "600"] }); +// DM Sans ships no Vietnamese subset, so `vi` uses Be Vietnam Pro — a +// geometric sans drawn for Vietnamese diacritics, which keeps the tone marks +// from colliding with ascenders the way a retrofitted face would. +const beVietnamPro = Be_Vietnam_Pro({ variable: "--font-sans", subsets: ["latin", "latin-ext", "vietnamese"], weight: ["400", "500", "600", "700"] }); + const devanagariSerif = Noto_Serif_Devanagari({ variable: "--font-serif", subsets: ["devanagari", "latin"], weight: ["400", "500", "600"] }); const devanagariSans = Noto_Sans_Devanagari({ variable: "--font-sans", subsets: ["devanagari", "latin"] }); @@ -24,6 +34,7 @@ const arabicSans = Noto_Sans_Arabic({ variable: "--font-sans", subsets: ["arabic const webFonts: Partial> = { latin: { serif: cormorant, sans: dmSans }, + vietnamese: { serif: cormorantVietnamese, sans: beVietnamPro }, cyrillic: { serif: cormorantCyrillic, sans: notoSansCyrillic }, devanagari: { serif: devanagariSerif, sans: devanagariSans }, arabic: { serif: arabicSerif, sans: arabicSans }, diff --git a/app/i18n/organs/vi.ts b/app/i18n/organs/vi.ts new file mode 100644 index 0000000..be30a38 --- /dev/null +++ b/app/i18n/organs/vi.ts @@ -0,0 +1,210 @@ +import type { OrganContentDictionary } from "../types"; + +export const organs: OrganContentDictionary = { + heart: { + name: "Tim", + system: "Hệ tim mạch", + description: "Một cơ quan cơ bơm máu đi khắp cơ thể, mang oxy và dưỡng chất đến từng tế bào.", + poetic: "Chiếc bơm không mỏi", + size: "Cỡ bằng nắm tay của bạn", + weight: "250–350 g", + location: "Sau xương ức, hơi lệch sang trái", + function: "Lưu thông máu giàu oxy", + dailyFact: "Đập khoảng 100.000 lần", + medical: "Nhịp điện của tim điều phối từng nhịp đập.", + bloodSupply: "Động mạch vành trái và phải", + funFact: "Tim đập khoảng 2,5 tỉ lần trong một đời người và bắt đầu đập từ trước khi bạn chào đời.", + tissue: "Mô cơ tim", + comparison: "Tim so với não", + conditions: ["Bệnh mạch vành", "Rối loạn nhịp tim", "Bệnh van tim", "Suy tim", "Bệnh cơ tim", "Viêm cơ tim", "Rung nhĩ", "Dị tật tim bẩm sinh"], + hotspots: { + "aorta": { label: "Động mạch chủ", detail: "Động mạch chính" }, + "left-atrium": { label: "Tâm nhĩ trái", detail: "Nhận máu giàu oxy" }, + "right-atrium": { label: "Tâm nhĩ phải", detail: "Nhận máu tĩnh mạch" }, + "left-ventricle": { label: "Tâm thất trái", detail: "Bơm máu đi khắp cơ thể" }, + "right-ventricle": { label: "Tâm thất phải", detail: "Bơm máu lên phổi" }, + "mitral": { label: "Van hai lá", detail: "Ngăn máu trào ngược" }, + }, + }, + brain: { + name: "Não", + system: "Hệ thần kinh", + description: "Trung tâm điều khiển của cơ thể, tích hợp cảm giác, trí nhớ, cảm xúc và vận động tinh vi.", + poetic: "Vũ trụ bên trong", + size: "Xấp xỉ hai nắm tay siết chặt", + weight: "1,3–1,4 kg", + location: "Được bảo vệ trong hộp sọ", + function: "Xử lý và điều phối tín hiệu", + dailyFact: "Dùng khoảng 20% năng lượng cơ thể", + medical: "Hàng tỉ nơ-ron giao tiếp với nhau bằng tín hiệu điện và hóa học.", + bloodSupply: "Động mạch cảnh trong và động mạch đốt sống", + funFact: "Bản thân não không có thụ thể đau — cơn đau đầu được cảm nhận ở các mô xung quanh nó.", + tissue: "Vỏ não", + comparison: "Não so với mắt", + conditions: ["Đau nửa đầu", "Đột quỵ", "Bệnh thoái hóa thần kinh", "Động kinh", "Chấn thương sọ não", "Viêm màng não", "Xơ cứng rải rác", "Phình mạch não"], + hotspots: { + "frontal": { label: "Thùy trán", detail: "Lập kế hoạch và vận động" }, + "parietal": { label: "Thùy đỉnh", detail: "Tích hợp cảm giác" }, + "temporal": { label: "Thùy thái dương", detail: "Trí nhớ và thính giác" }, + "cerebellum": { label: "Tiểu não", detail: "Thăng bằng và phối hợp" }, + }, + }, + lungs: { + name: "Phổi", + system: "Hệ hô hấp", + description: "Cặp cơ quan hút không khí vào và trao đổi oxy lấy khí carbonic qua một bề mặt rộng lớn, mỏng manh.", + poetic: "Hơi thở của sự sống", + size: "Mỗi lá cao khoảng 25 cm", + weight: "Khoảng 1 kg cho cả hai lá", + location: "Hai bên tim, trong lồng ngực", + function: "Trao đổi oxy lấy khí carbonic", + dailyFact: "Luân chuyển khoảng 11.000 L không khí", + medical: "Các phế nang gấp một bề mặt trao đổi rộng bằng sân tennis vào trong lồng ngực.", + bloodSupply: "Động mạch phổi và động mạch phế quản", + funFact: "Phổi phải có ba thùy còn phổi trái chỉ có hai, chừa một khuyết cho tim.", + tissue: "Mô phế nang", + comparison: "Phổi so với tim", + conditions: ["Hen phế quản", "Bệnh phổi tắc nghẽn mạn tính", "Viêm phổi", "Thuyên tắc phổi", "Xơ phổi", "Viêm phế quản", "Xơ nang", "Ung thư phổi"], + hotspots: { + "trachea": { label: "Khí quản", detail: "Dẫn khí vào phổi" }, + "right-lung": { label: "Phổi phải", detail: "Ba thùy" }, + "left-lung": { label: "Phổi trái", detail: "Hai thùy, chừa chỗ cho tim" }, + "bronchus": { label: "Phế quản", detail: "Đường dẫn khí phân nhánh" }, + "base": { label: "Đáy phổi", detail: "Tựa trên cơ hoành" }, + }, + }, + liver: { + name: "Gan", + system: "Hệ tiêu hóa", + description: "Một cơ quan chuyển hóa phi thường, lọc máu, xử lý dưỡng chất và sản xuất mật.", + poetic: "Nhà giả kim thầm lặng", + size: "Cỡ bằng một quả bóng bầu dục", + weight: "1,4–1,6 kg", + location: "Vùng bụng trên bên phải", + function: "Chuyển hóa, khử độc và tạo mật", + dailyFact: "Đảm nhiệm hơn 500 chức năng", + medical: "Gan có thể tái tạo một phần lớn mô đã mất.", + bloodSupply: "Động mạch gan và tĩnh mạch cửa", + funFact: "Đây là cơ quan duy nhất ở người có thể mọc lại đủ kích thước từ một phần nhỏ của chính nó.", + tissue: "Tiểu thùy gan", + comparison: "Gan so với ruột", + conditions: ["Gan nhiễm mỡ", "Viêm gan", "Xơ gan", "Sỏi mật", "Nhiễm sắt mô", "Ung thư gan", "Viêm gan tự miễn", "Tăng áp lực tĩnh mạch cửa"], + hotspots: { + "right-lobe": { label: "Thùy phải", detail: "Thùy gan lớn nhất" }, + "left-lobe": { label: "Thùy trái", detail: "Vắt qua đường giữa" }, + "portal": { label: "Tĩnh mạch cửa", detail: "Dòng máu giàu dưỡng chất đổ vào" }, + }, + }, + kidneys: { + name: "Thận", + system: "Hệ tiết niệu", + description: "Cặp cơ quan lọc, cân bằng dịch, điện giải, huyết áp và đào thải chất cặn bã.", + poetic: "Bộ lọc tài tình", + size: "Mỗi quả cỡ một con chuột máy tính", + weight: "120–170 g mỗi quả", + location: "Hai bên cột sống, dưới xương sườn", + function: "Lọc máu và tạo nước tiểu", + dailyFact: "Lọc khoảng 180 L dịch", + medical: "Các nephron tinh chỉnh thành phần hóa học của dòng máu.", + bloodSupply: "Động mạch thận", + funFact: "Thận thu hồi lại gần như toàn bộ những gì đã lọc — chỉ khoảng 1–2 L rời khỏi cơ thể dưới dạng nước tiểu.", + tissue: "Vỏ thận", + comparison: "Thận so với gan", + conditions: ["Sỏi thận", "Bệnh thận mạn", "Nhiễm khuẩn tiết niệu", "Viêm cầu thận", "Thận đa nang", "Tăng huyết áp do thận", "Tổn thương thận cấp", "Hội chứng thận hư"], + hotspots: { + "cortex": { label: "Vỏ thận", detail: "Lớp lọc phía ngoài" }, + "medulla": { label: "Tủy thận", detail: "Cô đặc nước tiểu" }, + "ureter": { label: "Niệu quản", detail: "Dẫn nước tiểu" }, + }, + }, + eyeball: { + name: "Mắt", + system: "Hệ giác quan", + description: "Một cơ quan cảm giác chính xác, biến ánh sáng hội tụ thành tín hiệu thần kinh được diễn giải thành thị giác.", + poetic: "Ô cửa dệt bằng ánh sáng", + size: "Đường kính khoảng 24 mm", + weight: "Khoảng 7,5 g", + location: "Nằm trong hốc mắt xương", + function: "Thu nhận và hội tụ ánh sáng", + dailyFact: "Thực hiện hàng nghìn chuyển động nhỏ", + medical: "Võng mạc là phần kéo dài của hệ thần kinh trung ương.", + bloodSupply: "Động mạch mắt", + funFact: "Giác mạc hoàn toàn không có mạch máu; nó lấy oxy trực tiếp từ không khí.", + tissue: "Các lớp võng mạc", + comparison: "Mắt so với não", + conditions: ["Cận thị", "Đục thủy tinh thể", "Tăng nhãn áp", "Thoái hóa điểm vàng", "Bong võng mạc", "Khô mắt", "Loạn thị", "Viêm kết mạc"], + hotspots: { + "cornea": { label: "Giác mạc", detail: "Bề mặt trong suốt hội tụ ánh sáng" }, + "iris": { label: "Mống mắt", detail: "Điều tiết lượng ánh sáng vào" }, + "optic": { label: "Thần kinh thị giác", detail: "Truyền tín hiệu thị giác" }, + }, + }, + intestine: { + name: "Ruột", + system: "Hệ tiêu hóa", + description: "Một đường tiêu hóa gấp khúc, nơi dưỡng chất được hấp thu và hệ vi sinh vật nâng đỡ sức khỏe toàn thân.", + poetic: "Khu vườn bên trong", + size: "Khoảng 6–7 m khi trải dài", + weight: "Thay đổi theo lượng chứa bên trong", + location: "Vùng bụng giữa và bụng dưới", + function: "Tiêu hóa và hấp thu dưỡng chất", + dailyFact: "Là nơi cư trú của hàng nghìn tỉ vi sinh vật", + medical: "Bề mặt của ruột được nhân lên nhờ các nếp gấp, nhung mao và vi nhung mao.", + bloodSupply: "Động mạch mạc treo tràng trên và dưới", + funFact: "Lớp niêm mạc ruột tự đổi mới sau vài ngày — tốc độ thay thế nhanh nhất trong mọi mô của cơ thể.", + tissue: "Nhung mao ruột", + comparison: "Ruột so với gan", + conditions: ["Hội chứng ruột kích thích", "Bệnh viêm ruột", "Bệnh celiac", "Viêm túi thừa", "Tắc ruột", "Polyp đại trực tràng", "Bệnh Crohn", "Bất dung nạp lactose"], + hotspots: { + "duodenum": { label: "Tá tràng", detail: "Đoạn đầu của ruột non" }, + "jejunum": { label: "Hỗng tràng", detail: "Vùng hấp thu chủ yếu" }, + "colon": { label: "Đại tràng", detail: "Thu hồi nước" }, + }, + }, + pancreas: { + name: "Tụy", + system: "Hệ nội tiết", + description: "Một tuyến kiêm hai vai trò: tiết enzyme tiêu hóa vào ruột và tiết hormone giữ ổn định đường huyết.", + poetic: "Người điều tiết thầm lặng", + size: "Dài khoảng 15 cm", + weight: "70–100 g", + location: "Sau dạ dày, vắt ngang vùng bụng trên", + function: "Enzyme tiêu hóa và insulin", + dailyFact: "Tạo khoảng 1,5 L dịch giàu enzyme", + medical: "Các tiểu đảo Langerhans tiết insulin và glucagon để cân bằng đường huyết.", + bloodSupply: "Động mạch lách và động mạch tá tụy", + funFact: "Chỉ chưa tới 2% khối lượng tụy làm nhiệm vụ tiết hormone; phần còn lại dành cho enzyme tiêu hóa.", + tissue: "Nang tuyến tụy", + comparison: "Tụy so với gan", + conditions: ["Viêm tụy", "Đái tháo đường type 1", "Ung thư tụy", "Đái tháo đường type 2", "Suy tụy ngoại tiết", "Nang tụy", "Viêm tụy do sỏi mật", "U tiết insulin"], + hotspots: { + "head": { label: "Đầu tụy", detail: "Được tá tràng ôm lấy" }, + "body": { label: "Thân tụy", detail: "Vắt ngang cột sống" }, + "tail": { label: "Đuôi tụy", detail: "Vươn tới lách" }, + "duct": { label: "Ống tụy", detail: "Dẫn enzyme xuống ruột" }, + }, + }, + skin: { + name: "Da", + system: "Hệ da và mô bao phủ", + description: "Cơ quan lớn nhất cơ thể — một hàng rào sống biết cảm nhận xúc giác, giữ nước và điều hòa thân nhiệt.", + poetic: "Đường biên sống", + size: "Khoảng 2 m² khi trải phẳng", + weight: "3,5–5 kg", + location: "Bao phủ toàn bộ cơ thể", + function: "Bảo vệ, cảm nhận và làm mát", + dailyFact: "Bong khoảng 500 triệu tế bào", + medical: "Ba lớp — biểu bì, trung bì và hạ bì — mỗi lớp đảm nhận một vai trò riêng.", + bloodSupply: "Đám rối mạch máu ở trung bì", + funFact: "Chỉ một xăng-ti-mét vuông da có thể chứa hàng trăm tuyến mồ hôi và hàng mét mạch máu.", + tissue: "Các lớp biểu bì", + comparison: "Da so với ruột", + conditions: ["Chàm", "Vảy nến", "Ung thư hắc tố", "Mụn trứng cá", "Viêm mô tế bào", "Viêm da tiếp xúc", "Trứng cá đỏ", "Bạch biến"], + hotspots: { + "epidermis": { label: "Biểu bì", detail: "Lớp bảo vệ ngoài cùng" }, + "dermis": { label: "Trung bì", detail: "Thần kinh, mạch máu và tuyến" }, + "hypodermis": { label: "Hạ bì", detail: "Mỡ và lớp cách nhiệt" }, + "follicle": { label: "Nang lông", detail: "Neo giữ từng sợi lông" }, + }, + }, +}; diff --git a/app/i18n/ui/vi.ts b/app/i18n/ui/vi.ts new file mode 100644 index 0000000..6b89797 --- /dev/null +++ b/app/i18n/ui/vi.ts @@ -0,0 +1,70 @@ +import type { UiDictionary } from "../types"; + +export const ui: UiDictionary = { + meta: { + title: "Anatomy Atelier — Học giải phẫu như một nghệ sĩ", + description: + "Khám phá các cơ quan 3D chi tiết theo chuẩn y khoa — tim, não, phổi, gan, thận, mắt, ruột, tụy và da — trong một xưởng giải phẫu tương tác đầy tinh tế.", + ogTitle: "Anatomy Atelier — Học giải phẫu như một nghệ sĩ", + ogDescription: "Học giải phẫu như một nghệ sĩ qua các tiêu bản 3D sống động, chi tiết theo chuẩn y khoa.", + imageAlt: "Tiêu bản tim giải phẫu lơ lửng trên bệ đỡ, bên cạnh là logo chữ Anatomy Atelier", + }, + brand: { tagline: "Học giải phẫu như một nghệ sĩ", home: "Trang chủ Anatomy Atelier" }, + nav: { explore: "Khám phá", systems: "Hệ cơ quan", lessons: "Bài học", library: "Thư viện", notes: "Ghi chú" }, + search: { placeholder: "Tìm cơ quan, chủ đề…" }, + profile: { open: "Mở hồ sơ người học" }, + language: { label: "Ngôn ngữ", choose: "Chọn ngôn ngữ" }, + library: { + title: "Thư viện cơ quan", open: "Mở thư viện cơ quan", close: "Đóng thư viện", saved: "Cơ quan đã lưu", + viewAll: "Xem tất cả cơ quan", + quoteLine1: "Học tập là", quoteLine2: "một hành động của sự tò mò.", quoteSign: "Cứ khám phá tiếp nhé!", + }, + tools: { + label: "Công cụ xem 3D", rotate: "Xoay", zoom: "Thu phóng", isolate: "Tách riêng", + section: "Mặt cắt", layers: "Lớp", compare: "So sánh", reset: "Đặt lại", + }, + viewer: { + title: "Trình xem tương tác {organ}", + canvas: "Mô hình giải phẫu 3D tương tác. Kéo để xoay, cuộn để thu phóng và bấm vào một chấm để đọc về cấu trúc đó.", + tip: "Mẹo", tipDrag: "Kéo để xoay", tipScroll: "Cuộn để thu phóng", tipClick: "Bấm vào một chấm để tìm hiểu thêm", + loading: "Đang chuẩn bị {organ}", autoRotate: "Tự động xoay", + caption: "Tiêu bản 3D · bấm vào một chấm để khám phá", structures: "Các cấu trúc trong tiêu bản này", + }, + info: { + kicker: "{organ}", keyFacts: "Thông tin chính", size: "Kích thước", weight: "Khối lượng", daily: "Mỗi ngày", + location: "Vị trí", bloodSupply: "Nguồn cấp máu", function: "Chức năng", + medical: "Ý nghĩa y học", didYouKnow: "Bạn có biết", viewLesson: "Xem bài học", + animate: "Hoạt ảnh", quiz: "Trắc nghiệm", compare: "So sánh", + }, + compare: { + title: "So sánh cơ quan", comparing: "Đang so sánh", reference: "Đối chiếu", + primaryRole: "Vai trò chính", scale: "Tỉ lệ", vs: "so với", close: "Đóng so sánh", + }, + cards: { + resources: "Tài liệu học về {organ}", + microscopic: "Góc nhìn vi thể", compareOrgans: "So sánh các cơ quan", functionAnimation: "Hoạt ảnh chức năng", + clinicalNotes: "Ghi chú lâm sàng", whereItWorks: "Hoạt động ở đâu", commonConditions: "Bệnh lý thường gặp", + exploreTissue: "Khám phá mô", openComparison: "Mở phần so sánh", playAnimation: "Phát hoạt ảnh", + seeAll: "Xem tất cả", seeSystem: "Xem hệ cơ quan", + playAria: "Phát hoạt ảnh chức năng của {organ}", systemAria: "Xem vị trí của {organ} trong cơ thể", + }, + quiz: { + start: "Bắt đầu bài trắc nghiệm ghi nhãn", find: "Hãy tìm", progress: "{current} trên {total}", + correct: "Chính xác", wrong: "Chưa đúng", reveal: "Đó là {label}", answer: "{label} được đánh dấu màu xanh lá", + done: "Hoàn thành bài trắc nghiệm", score: "Đúng {score} trên {total}", retry: "Thử lại", + exit: "Thoát trắc nghiệm", hint: "Bấm vào chấm tương ứng trên mô hình", + }, + modal: { + guided: "Khám phá có hướng dẫn", close: "Đóng", continueExploring: "Tiếp tục khám phá", + quizTitle: "Trắc nghiệm nhanh về {organ}", motionTitle: "{organ} chuyển động", + bodyTitle: "{organ} trong cơ thể", insideTitle: "Bên trong {organ}", + quizPrompt: "Phát biểu nào mô tả đúng nhất về {organ}?", + quizA: "Nó đảm nhận một vai trò chuyên biệt để duy trì hoạt động của cơ thể", + quizB: "Nó hoạt động hoàn toàn độc lập", + quizC: "Nó chỉ hoạt động khi ta ngủ", + lessonBody: + "Hãy lần theo các cấu trúc được làm nổi bật, xoay tiêu bản và kết nối hình thái với chức năng. Khoảnh khắc học ngắn này được thiết kế để xây dựng một mô hình tư duy bền vững.", + systemIntro: "{location}. Hãy lần theo cách {organ} kết nối với phần còn lại của cơ thể.", + system: "Hệ cơ quan", primaryRole: "Vai trò chính", bloodSupply: "Nguồn cấp máu", + }, +};