/* ============================================================ * Diablo2D — i18n.js : English / Vietnamese localization * ============================================================ */ 'use strict'; window.D2 = window.D2 || {}; (function (D2) { const dict = { en: { /* generic */ ok: 'OK', cancel: 'Cancel', close: 'Close', yes: 'Yes', no: 'No', back: 'Back', confirm: 'Confirm', none: 'None', level_short: 'Lv', /* title */ 'title.newgame': 'New Game', 'title.continue': 'Continue', 'title.settings': 'Settings', 'title.help': 'How to Play', 'title.credits': 'Credits', 'title.tagline': 'Shadows of Tristram', 'title.subtitle': 'A dark action-RPG for your browser', 'title.no_save': 'No saved hero found.', 'title.confirm_overwrite': 'Starting a new game will overwrite your saved hero. Continue?', 'title.saved_hero': 'Saved Hero', 'title.delete_save': 'Delete Save', 'title.confirm_delete': 'Permanently delete the saved hero?', /* classes */ 'class.crusader.name': 'Crusader', 'class.crusader.desc': 'A holy warrior clad in heavy armor. Wades into melee with sweeping strikes and unbreakable defenses.', 'class.ranger.name': 'Shadow Huntress', 'class.ranger.desc': 'A swift rogue who strikes from the shadows with bow and blade, bleeding her prey from afar.', 'class.sorceress.name': 'Sorceress', 'class.sorceress.desc': 'Master of fire, frost and storm. Fragile in body, devastating in arcane power.', 'class.select': 'Choose Your Fate', 'class.play': 'Begin Descent', /* stats */ 'stat.strength': 'Strength', 'stat.dexterity': 'Dexterity', 'stat.vitality': 'Vitality', 'stat.energy': 'Energy', 'stat.damage': 'Damage', 'stat.armor': 'Armor', 'stat.crit': 'Crit Chance', 'stat.critdmg': 'Crit Damage', 'stat.speed': 'Move Speed', 'stat.magicfind': 'Magic Find', 'stat.lifelench': 'Life per Kill', 'stat.fire': 'Fire Resist', 'stat.cold': 'Cold Resist', 'stat.lightning': 'Lightning Resist', 'stat.poison': 'Poison Resist', 'stat.points': 'Attribute Points', 'stat.skillpoints': 'Skill Points', /* ui panels */ 'ui.inventory': 'Inventory', 'ui.character': 'Character', 'ui.skills': 'Skills', 'ui.stash': 'Stash', 'ui.vendor': 'Blacksmith', 'ui.healer': 'Healer', 'ui.questlog': 'Quest Log', 'ui.map': 'World Map', 'ui.help': 'How to Play', 'ui.equip.weapon': 'Weapon', 'ui.equip.offhand': 'Off-hand', 'ui.equip.head': 'Head', 'ui.equip.chest': 'Body', 'ui.equip.hands': 'Hands', 'ui.equip.feet': 'Feet', 'ui.equip.amulet': 'Amulet', 'ui.equip.ring1': 'Ring', 'ui.equip.ring2': 'Ring', 'ui.gold': 'Gold', 'ui.sell': 'Sell', 'ui.buy': 'Buy', 'ui.repair_none': '', 'ui.heal_full': 'Full Restore', 'ui.price': 'Price', 'ui.empty_slot': 'Empty', 'ui.drop_confirm': 'This item will be destroyed. Drop it?', /* hotbar */ 'hb.health_potion': 'Health Potion', 'hb.mana_potion': 'Mana Potion', 'hb.inventory': 'Inventory (I)', 'hb.character': 'Character (C)', 'hb.skills': 'Skills (T)', 'hb.quests': 'Quest Log (J)', 'hb.map': 'Map (M)', 'hb.help': 'Help (F1)', /* messages */ 'msg.levelup': 'Level Up! Press C to assign points.', 'msg.skillpoint': 'New skill learned! Press T to view skills.', 'msg.not_enough_mana': 'Not enough mana!', 'msg.skill_cooldown': 'Skill is not ready.', 'msg.inventory_full': 'Inventory is full!', 'msg.potion_none': 'No potions left!', 'msg.boss_spawn': 'A great evil awakens...', 'msg.boss_slain': 'The guardian has fallen!', 'msg.act_clear': 'Act complete! The waypoint stirs...', 'msg.saved': 'Game saved.', 'msg.hardcore_death': 'Your hardcore hero has perished. The record burns.', 'msg.town_portal': 'Returned to town.', 'msg.elite_slain': 'Champion slain!', 'msg.shrine': 'You touch the shrine...', /* quests */ 'quest.main_prefix': 'Act {0}: ', 'quest.descend': 'Descend to depth {0}', 'quest.kill_boss': 'Slay {0}', 'quest.done': 'Complete', /* death / victory */ 'death.title': 'YOU HAVE DIED', 'death.subtitle': 'Even heroes fall... but darkness always offers another chance.', 'death.respawn': 'Awaken in Town', 'death.title_screen': 'Return to Title', 'victory.title': 'THE LORD OF TERROR IS VANQUISHED', 'victory.subtitle': 'Tristram breathes again — yet the depths always call louder.', 'victory.continue': 'Continue in Torment {0}', 'victory.title_screen': 'Return to Title', 'victory.stats': 'Run Statistics', /* settings */ 'set.master': 'Master Volume', 'set.music': 'Music', 'set.sfx': 'Sound Effects', 'set.lang': 'Language', 'set.shake': 'Screen Shake', 'set.dmgnum': 'Damage Numbers', 'set.labels': 'Item Labels', 'set.hardcore': 'Hardcore Mode (new game)', 'set.export': 'Export Save Code', 'set.import': 'Import Save Code', 'set.wipe': 'Erase All Data', 'set.copy_ok': 'Copied!', 'set.import_bad': 'Invalid save code.', 'set.import_ok': 'Save imported!', 'set.confirm_wipe': 'Erase ALL saved data? This cannot be undone.', /* help */ 'help.move': 'Left click — move / attack. Hold to keep moving toward cursor.', 'help.combat': 'Right click & keys 1–4 — cast skills. Q / E — potions.', 'help.items': 'Hold Alt to reveal ground item labels. Click an item to pick up.', 'help.panels': 'I inventory · C character · T skills · J quests · M map · Esc pause.', 'help.tip1': 'Champions glow with an aura — they hit harder but drop better loot.', 'help.tip2': 'Shrines grant powerful temporary blessings.', 'help.tip3': 'Resistances matter more than armor against elemental bosses.', 'help.keys_title': 'Controls', /* town npcs */ 'npc.charsi.name': 'Charsi', 'npc.akara.name': 'Akara', 'npc.kashya.name': 'Kashya', 'npc.cain.name': 'Deckard Cain', 'npc.gheed.name': 'Gheed', 'npc.stash.name': 'Camp Storage', 'msg.quest_accepted': 'Quest accepted: {0}', 'msg.quest_reward': 'Quest complete! +{0} gold', 'quest.seek_hint': 'Visit camp — new tasks await.', 'ui.rare_item': 'a Rare item', 'npc.charsi.name': 'Charsi', 'npc.akara.name': 'Akara', 'npc.kashya.name': 'Kashya', 'npc.cain.name': 'Deckard Cain', 'npc.gheed.name': 'Gheed', 'npc.stash.name': 'Kho trại', 'msg.quest_accepted': 'Đã nhận nhiệm vụ: {0}', 'msg.quest_reward': 'Nhiệm vụ hoàn thành! +{0} vàng', 'quest.seek_hint': 'Hãy ghé trại — có việc mới đang chờ.', 'ui.rare_item': 'một món Hiếm', 'npc.charsi.greet': 'Steel keeps you alive down there. Browse my wares.', 'npc.akara.greet': 'The Light mend you. What do you need, child?', 'npc.kashya.greet': 'The camp needs a blade like yours. We have work.', 'npc.cain.greet': 'Stay awhile and listen…', 'npc.gheed.greet': 'Psst. Finest goods in the camp — provenance uncertain.', 'npc.stash.greet': 'Your vault awaits.', 'npc.waypoint.greet': 'Where does fate pull you, hero?', 'ui.accept': 'Accept quest', 'ui.turn_in': 'Turn in', 'ui.reward': 'Reward', 'ui.later': 'Not now', 'ui.lore': 'Ask for lore', 'ui.buy_tome': 'Buy Skill Tome (+1 skill pt)', 'ui.respec': 'Respec all points', 'ui.gamble': 'Gamble for goods', 'ui.gamble_hint': 'Rarity unknown until bought…', 'ui.quest_done_return': 'Return to {0}', 'ui.tome_bought': 'Knowledge burns behind your eyes… (+1 skill point)', 'ui.respec_done': 'Your training is undone. Points refunded.', 'ui.gamble_win': 'Fortune favors you… this time.', 'quest.cull': 'Cull the Fallen', 'quest.cull.desc': 'Slay {0} denizens of the Cathedral depths. Kashya counts every kill.', 'quest.boss': 'The {0}', 'quest.boss.desc': 'Descend to the lair and destroy {0}. The camp will not rest until it is done.', 'quest.torment': 'Echoes of Terror', 'quest.torment.desc': 'Malgor is dead, yet his echo festers. Open torment {0} and cull it anew.', 'town.enter': 'Tristram Outpost — Sanctuary', /* misc */ 'floor.depth': 'Depth {0}', 'act.names.0': 'The Ravaged Cathedral', 'act.names.1': 'The Weeping Catacombs', 'act.names.2': 'The Fungal Depths', 'act.names.3': "Hell's Threshold", torment: 'Torment {0}', 'loading.tips.0': 'Elites drop enchanted loot. Hunt the glowing ones.', 'loading.tips.1': 'Potions refill each time you visit town.', 'loading.tips.2': 'Fire melts flesh; cold freezes bone. Bring both.', 'loading.tips.3': 'Barrels and urns hide coins... and sometimes worse.', 'loading.tips.4': 'Magic Find increases rare and legendary drops.', 'credits.line1': 'Design, code, art & audio — procedurally generated, no external assets.', 'credits.line2': 'Inspired by the classics that defined the genre.', }, vi: { ok: 'Đồng ý', cancel: 'Hủy', close: 'Đóng', yes: 'Có', no: 'Không', back: 'Quay lại', confirm: 'Xác nhận', none: 'Không', level_short: 'Cấp', 'title.newgame': 'Chơi mới', 'title.continue': 'Tiếp tục', 'title.settings': 'Cài đặt', 'title.help': 'Hướng dẫn chơi', 'title.credits': 'Thông tin', 'title.tagline': 'Bóng Đêm Tristram', 'title.subtitle': 'Action-RPG tối giản chạy ngay trên trình duyệt', 'title.no_save': 'Không tìm thấy bản lưu nào.', 'title.confirm_overwrite': 'Bắt đầu game mới sẽ xóa hero đã lưu. Tiếp tục?', 'title.saved_hero': 'Hero đã lưu', 'title.delete_save': 'Xóa bản lưu', 'title.confirm_delete': 'Xóa vĩnh viễn hero đã lưu?', 'class.crusader.name': 'Thập Tự Quân', 'class.crusader.desc': 'Chiến binh thánh thiện trong bộ giáp nặng, quét sạch kẻ thù bằng chém rộng và phòng thủ thép.', 'class.ranger.name': 'Nữ Thợ Săn Bóng Đêm', 'class.ranger.desc': 'Nữ sát thủ nhanh nhẹn, hạ gục con mồi từ xa bằng cung tên độc và bóng tối.', 'class.sorceress.name': 'Pháp Sư', 'class.sorceress.desc': 'Bậc thầy hỏa, băng và lôi. Thân yếu nhưng sức mạnh huyền thuật tàn khốc.', 'class.select': 'Chọn Số Phận Của Bạn', 'class.play': 'Bắt Đầu Hạ Sơn', 'stat.strength': 'Sức mạnh', 'stat.dexterity': 'Nhuệ', 'stat.vitality': 'Sinh lực', 'stat.energy': 'Năng lượng', 'stat.damage': 'Sát thương', 'stat.armor': 'Giáp', 'stat.crit': 'Tỷ lệ chí mạng', 'stat.critdmg': 'ST chí mạng', 'stat.speed': 'Tốc độ chạy', 'stat.magicfind': 'May mắn tìm đồ', 'stat.lifelench': 'Hồi máu mỗi lần hạ', 'stat.fire': 'Kháng Hỏa', 'stat.cold': 'Kháng Băng', 'stat.lightning': 'Kháng Lôi', 'stat.poison': 'Kháng Độc', 'stat.points': 'Điểm thuộc tính', 'stat.skillpoints': 'Điểm kỹ năng', 'ui.inventory': 'Túi đồ', 'ui.character': 'Nhân vật', 'ui.skills': 'Kỹ năng', 'ui.stash': 'Kho đồ', 'ui.vendor': 'Thợ Rèn', 'ui.healer': 'Pháp Sư Trị Liệu', 'ui.questlog': 'Nhật nhiệm vụ', 'ui.map': 'Bản đồ thế giới', 'ui.help': 'Hướng dẫn', 'ui.equip.weapon': 'Vũ khí', 'ui.equip.offhand': 'Tay trái', 'ui.equip.head': 'Đầu', 'ui.equip.chest': 'Thân', 'ui.equip.hands': 'Tay', 'ui.equip.feet': 'Chân', 'ui.equip.amulet': 'Mặt dây', 'ui.equip.ring1': 'Nhẫn', 'ui.equip.ring2': 'Nhẫn', 'ui.gold': 'Vàng', 'ui.sell': 'Bán', 'ui.buy': 'Mua', 'ui.heal_full': 'Hồi phục hoàn toàn', 'ui.price': 'Giá', 'ui.empty_slot': 'Trống', 'ui.drop_confirm': 'Vật phẩm sẽ bị phá hủy. Vứt bỏ?', 'hb.health_potion': 'Bình máu', 'hb.mana_potion': 'Bình mana', 'hb.inventory': 'Túi đồ (I)', 'hb.character': 'Nhân vật (C)', 'hb.skills': 'Kỹ năng (T)', 'hb.quests': 'Nhiệm vụ (J)', 'hb.map': 'Bản đồ (M)', 'hb.help': 'Trợ giúp (F1)', 'msg.levelup': 'Lên cấp! Nhấn C để cộng điểm.', 'msg.skillpoint': 'Kỹ năng mới! Nhấn T để xem kỹ năng.', 'msg.not_enough_mana': 'Không đủ mana!', 'msg.skill_cooldown': 'Kỹ năng chưa hồi xong.', 'msg.inventory_full': 'Túi đồ đầy!', 'msg.potion_none': 'Hết bình hồi máu!', 'msg.boss_spawn': 'Một ma lực khổng lồ thức dậy...', 'msg.boss_slain': 'Ác thần đã bị hạ!', 'msg.act_clear': 'Hoàn thành chương! Điểm dịch chuyển rung lên...', 'msg.saved': 'Đã lưu game.', 'msg.hardcore_death': 'Hero Hardcore của bạn đã chết. Bản lưu bị thiêu rụi.', 'msg.town_portal': 'Đã về trấn.', 'msg.elite_slain': 'Đã hạ tinh anh!', 'msg.shrine': 'Bạn chạm vào đền thờ...', 'quest.main_prefix': 'Chương {0}: ', 'quest.descend': 'Hạ xuống độ sâu {0}', 'quest.kill_boss': 'Hạ gục {0}', 'quest.done': 'Hoàn thành', 'death.title': 'BẠN ĐÃ CHẾT', 'death.subtitle': 'Anh hùng cũng có thể ngã... nhưng bóng tối luôn cho thêm một cơ hội.', 'death.respawn': 'Thức dậy ở trấn', 'death.title_screen': 'Về màn hình chính', 'victory.title': 'CHÚA TỂ KINH HOÀNG ĐÃ BỊ TIÊU DIỆT', 'victory.subtitle': 'Tristram lại được thở — nhưng vực sâu luôn gọi to hơn.', 'victory.continue': 'Tiếp tục ở Torment {0}', 'victory.title_screen': 'Về màn hình chính', 'victory.stats': 'Thống kê chuyến chiến', 'set.master': 'Âm lượng tổng', 'set.music': 'Nhạc nền', 'set.sfx': 'Hiệu ứng âm thanh', 'set.lang': 'Ngôn ngữ', 'set.shake': 'Rung màn hình', 'set.dmgnum': 'Số sát thương', 'set.labels': 'Nhãn đồ trên đất', 'set.hardcore': 'Chế độ Hardcore (chơi mới)', 'set.export': 'Xuất mã lưu', 'set.import': 'Nhập mã lưu', 'set.wipe': 'Xóa toàn bộ dữ liệu', 'set.copy_ok': 'Đã sao chép!', 'set.import_bad': 'Mã lưu không hợp lệ.', 'set.import_ok': 'Đã nhập bản lưu!', 'set.confirm_wipe': 'Xóa TOÀN BỘ dữ liệu đã lưu? Không thể hoàn tác.', 'help.move': 'Chuột trái — di chuyển / tấn công. Giữ để liên tục đi theo con trỏ.', 'help.combat': 'Chuột phải & phím 1–4 — dùng kỹ năng. Q / E — bình máu, bình mana.', 'help.items': 'Giữ Alt để hiện nhãn đồ trên đất. Nhấp vào món để nhặt.', 'help.panels': 'I túi đồ · C nhân vật · T kỹ năng · J nhiệm vụ · M bản đồ · Esc tạm dừng.', 'help.tip1': 'Tinh anh phát sáng quanh thân — mạnh hơn nhưng rớt đồ tốt hơn.', 'help.tip2': 'Đền thờ ban phước tạm thời rất mạnh.', 'help.tip3': 'Kháng nguyên tố quan trọng hơn giáp khi đấu boss hệ elemental.', 'help.keys_title': 'Điều khiển', 'npc.charsi.greet': 'Thép giữ bạn sống dưới đó. Xem hàng của ta đi.', 'npc.akara.greet': 'Ánh Sáng chữa lành ngươi. Con cần gì nào?', 'npc.kashya.greet': 'Trại cần một lưỡi kiếm như ngươi. Ta có việc đây.', 'npc.cain.greet': 'Ở lại nghe ta kể chuyện này…', 'npc.gheed.greet': 'Này. Hàng tốt nhất trại — nguồn gốc thì… khỏi hỏi.', 'npc.stash.greet': 'Kho của bạn đang chờ.', 'npc.waypoint.greet': 'Định mệnh đang kéo bạn đến đâu, anh hùng?', 'ui.accept': 'Nhận nhiệm vụ', 'ui.turn_in': 'Trả nhiệm vụ', 'ui.reward': 'Thưởng', 'ui.later': 'Để sau', 'ui.lore': 'Hỏi chuyện xưa', 'ui.buy_tome': 'Mua Sách Kỹ năng (+1 điểm)', 'ui.respec': 'Phân bổ lại toàn bộ điểm', 'ui.gamble': 'Đánh bạc đổi hàng', 'ui.gamble_hint': 'Đến khi mua mới biết hiếm hay thường…', 'ui.quest_done_return': 'Quay về gặp {0}', 'ui.tome_bought': 'Tri thức bừng cháy trong đầu con… (+1 điểm kỹ năng)', 'ui.respec_done': 'Toàn bộ điểm đã hoàn trả.', 'ui.gamble_win': 'Thần may mắn đứng về phía ngươi… lần này.', 'quest.cull': 'Thanh tẩy Kẻ ngã ngã', 'quest.cull.desc': 'Hạ {0} sinh vật trong hang động. Kashya đếm từng mạng.', 'quest.boss': '{0}', 'quest.boss.desc': 'Xuống tới hang ổ và tiêu diệt {0}. Trại sẽ không yên khi nó còn sống.', 'quest.torment': 'Ám ảnh Khủng khiếp', 'quest.torment.desc': 'Malgor chết rồi nhưng bóng ma nó còn. Mở torment {0} và thanh tẩy lại.', 'town.enter': 'Trấn Tristram — Nơi Tôn Nghiêm', 'floor.depth': 'Độ sâu {0}', 'act.names.0': 'Nhà thờ hoang tàn', 'act.names.1': 'Hầm mộ than khóc', 'act.names.2': 'Vực nấm sâu thẳm', 'act.names.3': 'Ngưỡng cửa Địa Ngục', torment: 'Torment {0}', 'loading.tips.0': 'Tinh anh rớt đồ phù phép. Săn những con phát sáng.', 'loading.tips.1': 'Bình hồi máu được nạp lại mỗi khi về trấn.', 'loading.tips.2': 'Lửa thiêu thịt; băng đóng băng xương. Mang cả hai.', 'loading.tips.3': 'Thùng rượu và lư đồng giấu vàng... đôi khi còn giấu cả thứ khác.', 'loading.tips.4': 'May mắn tìm đồ tăng tỷ lệ rớt đồ hiếm và huyền thoại.', 'credits.line1': 'Thiết kế, lập trình, hình ảnh & âm nhạc — sinh ra thủ tục, không dùng tài nguyên ngoài.', 'credits.line2': 'Lấy cảm hứng từ những tựa game kinh điển định hình thể loại.', }, }; let lang = 'en'; function t(key, ...vars) { let s = (dict[lang] && dict[lang][key]) ?? dict.en[key] ?? key; vars.forEach((v, i) => { s = s.replaceAll('{' + i + '}', String(v)); }); return s; } function setLang(l) { lang = (dict[l] ? l : 'en'); if (typeof document !== 'undefined') document.documentElement.lang = lang; } function getLang() { return lang; } function languages() { return Object.keys(dict); } /* apply data-i18n attributes inside a root element */ function applyDom(root = document) { root.querySelectorAll('[data-i18n]').forEach(el => { el.textContent = t(el.getAttribute('data-i18n')); }); root.querySelectorAll('[data-i18n-title]').forEach(el => { el.title = t(el.getAttribute('data-i18n-title')); }); } D2.i18n = { t, setLang, getLang, languages, applyDom, dict }; })(window.D2);