로스트아크 북미 미터기 한글패치
// ==UserScript==
// @name lostark bible korean
// @namespace http://tampermonkey.net/
// @version 1.1
// @description 로스트아크 북미 미터기 한글패치
// @author AGAK
// @match https://lostark.bible/*
// @icon https://lostark.bible/favicon.png
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const customTranslations = {
"Raid Statistics": "레이드 통계",
"Absolute Performance": "절대 지표",
"Relative Performance": "상대 지표",
"Details": "상세 정보",
"General": "일반",
"Raid Performance": "레이드 통계",
"Class Loadouts": "클래스 세팅",
"Ark Passive": "아크 패시브",
"Filters": "필터",
"Raid": "레이드",
"Difficulty": "난이도",
"The First": "더 퍼스트",
"Filter By": "필터 기준",
"Item Level": "아이템 레벨",
"Combat Power": "전투력",
"Show stats from": "통계 범위 :",
"Damage Type": "데미지 타입",
"Additional Options": "추가 옵션",
"Include Bus": "버스 포함",
"Include Weird": "이상한 파티 포함",
"Patch": "패치 버전",
"Call of the Wildsoul": "환수사 추가",
"April 2025": "2025년 4월",
"July 2025": "2025년 7월",
"November 2025": "2025년 11월",
"January 2026": "2026년 1월",
"March 2026": "2026년 3월",
"Sort By": "정렬 기준",
"Floor": "저점",
"Q1": "하위 25%",
"Median": "평균",
"Q3": "상위 25%",
"Ceiling": "고점",
"Best": "최고기록",
"Popularity": "표본수",
"Normal": "노말",
"Hard": "하드",
"Extreme": "익스트림",
"Epic Raid": "에픽 레이드",
"Kazeros Raid": "카제로스 레이드",
"Event Raid": "이벤트 레이드",
"Assault Raid": "강습 레이드",
"Behemoth, the Storm Commander": "베히모스 - 1관문",
"Behemoth, Cruel Storm Slayer": "베히모스 - 2관문",
"Akkan, Lord of Death": "에기르 - 1관문",
"Aegir, the Oppressor": "에기르 - 2관문",
"Narok the Butcher": "아브렐슈드 - 1관문",
"Phantom Manifester Brelshaza": "아브렐슈드 - 2관문",
"Infernas": "모르둠 - 1관문",
"Blossoming Fear, Naitreya": "모르둠 - 2관문",
"Mordum, the Abyssal Punisher": "모르둠 - 3관문",
"Brelshaza, Ember in the Ashes": "아르모체 - 1관문",
"Armoche, Sentinel of the Abyss": "아르모체 - 2관문",
"Abyss Lord Kazeros": "카제로스 - 1관문",
"Death Incarnate Kazeros": "카제로스 - 2관문",
"Thaemine, Conqueror of Stars": "카멘 - 4관문",
"Flame of Darkness, Tarkal": "타르칼 - 1관문",
"Behemoth - Gate 1": "베히모스 - 1관문",
"Behemoth - Gate 2": "베히모스 - 2관문",
"Aegir - Gate 1": "에기르 - 1관문",
"Aegir - Gate 2": "에기르 - 2관문",
"Brelshaza - Gate 1": "아브렐슈드 - 1관문",
"Brelshaza - Gate 2": "아브렐슈드 - 2관문",
"Mordum - Gate 1": "모르둠 - 1관문",
"Mordum - Gate 2": "모르둠 - 2관문",
"Mordum - Gate 3": "모르둠 - 3관문",
"Armoche - Gate 1": "아르모체 - 1관문",
"Armoche - Gate 2": "아르모체 - 2관문",
"Kazeros - Gate 1": "카제로스 - 1관문",
"Kazeros - Gate 2": "카제로스 - 2관문",
"Thaemine - Gate 4": "카멘 - 4관문",
"Tarkal - Gate 1": "타르칼(강습) - 1관문",
"DPS Performance": "DPS 통계",
"Mayhem": "광기",
"Berserker Technique": "비기",
"Gravity Training": "중수",
"Rage Hammer": "분망",
"Combat Readiness": "전태",
"Lone Knight": "고기",
"Judgment": "심판자",
"Predator": "포식",
"Punisher": "처단",
"Shining Knight": "딜키리",
"Grace of the Empress": "황후",
"Order of the Emperor": "황제",
"Communication Overflow": "교감",
"Master Summoner": "상소",
"Igniter": "점화",
"Reflux": "환류",
"True Courage": "진용",
"Pinnacle": "절정",
"Control": "절제",
"Ultimate Skill: Taijutsu": "체술",
"Shock Training": "충단",
"Esoteric Skill Enhancement": "오의",
"First Intention": "초심",
"Energy Overflow": "역천",
"Robust Spirit": "세맥",
"Deathblow": "일격",
"Esoteric Flurry": "난무",
"Asura's Path": "수라",
"Brawl King Storm": "권왕",
"Hunger": "갈증",
"Lunar Voice": "달소",
"Demonic Impulse": "충동",
"Perfect Suppression": "억제",
"Remaining Energy": "잔재",
"Surge": "버스트",
"Full Moon Harvester": "만월의",
"Night's Edge": "그믐",
"Enhanced Weapon": "전탄",
"Pistoleer": "핸건",
"Evolutionary Legacy": "유산",
"Arthetinean Skill": "기술",
"Barrage Enhancement": "포강",
"Firepower Enhancement": "화강",
"Loyal Companion": "두동",
"Death Strike": "죽습",
"Peacemaker": "피메",
"Time to Hunt": "사시",
"Recurrence": "회귀",
"Wind Fury": "질풍",
"Drizzle": "이슬비",
"Ferality": "야성",
"Phantom Beast Awakening": "환각",
"Hellfire Successor": "업화",
"Dreadful Roar": "드드",
"Berserker": "버서커",
"Destroyer": "디스트로이어",
"Gunlancer": "워로드",
"Paladin": "홀리나이트",
"Slayer": "슬레이어",
"Valkyrie": "발키리",
"Arcana": "아르카나",
"Summoner": "서머너",
"Sorceress": "소서리스",
"Bard": "바드",
"Artillerist": "블래스터",
"Sharpshooter": "호크아이",
"Deadeye": "데빌헌터",
"Machinist": "스카우터",
"Gunslinger": "건슬링어",
"Glaivier": "창술사",
"Soulfist": "기공사",
"Scrapper": "인파이터",
"Wardancer": "배틀마스터",
"Striker": "스트라이커",
"Breaker": "브레이커",
"Deathblade": "블레이드",
"Reaper": "리퍼",
"Shadowhunter": "데모닉",
"Souleater": "소울이터",
"Artist": "도화가",
"Aeromancer": "기상술사",
"Wildsoul": "환수사",
"Guardianknight": "가디언나이트",
"Support Uptime": "서폿 통계",
"H.A. Skill": "초각성 스킬",
"Identity": "아덴",
"Brand": "낙인",
"AP": "공증"
};
const sortedKeys = Object.keys(customTranslations).sort((a, b) => b.length - a.length);
function applyTranslation(node) {
if (node.nodeType === Node.TEXT_NODE && node.textContent.trim() !== '') {
let originalText = node.textContent;
let translatedText = originalText;
for (const key of sortedKeys) {
const value = customTranslations[key];
if (translatedText.includes(key)) {
const regex = new RegExp(escapeRegExp(key), 'g');
translatedText = translatedText.replace(regex, value);
}
}
if (originalText !== translatedText) {
node.textContent = translatedText;
}
}
}
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function translateElementContent(element) {
const walker = document.createTreeWalker(
element,
NodeFilter.SHOW_TEXT,
null,
false
);
let node;
while ((node = walker.nextNode())) {
if (node.parentNode.tagName !== 'SCRIPT' &&
node.parentNode.tagName !== 'STYLE' &&
!node.parentNode.hasAttribute('data-no-translate') &&
!node.parentNode.classList.contains('no-translate')) {
applyTranslation(node);
}
}
}
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
translateElementContent(node);
} else if (node.nodeType === Node.TEXT_NODE) {
applyTranslation(node);
}
});
} else if (mutation.type === 'characterData') {
applyTranslation(mutation.target);
}
});
});
window.addEventListener('load', () => {
translateElementContent(document.body);
if (document.title) {
let translatedTitle = document.title;
for (const key of sortedKeys) {
const value = customTranslations[key];
if (translatedTitle.includes(key)) {
const regex = new RegExp(escapeRegExp(key), 'g');
translatedTitle = translatedTitle.replace(regex, value);
}
}
document.title = translatedTitle;
}
observer.observe(document.body, {
childList: true,
subtree: true,
characterData: true
});
});
})();