// ==UserScript==
// @name BIS 표 한글화
// @namespace ㅇㅇ
// @version 7.11.04
// @description 스탯과 장비.. 기타 등등을 한국어로 보여줌
// @match https://etro.gg/*
// @match https://xivgear.app/*
// @grant GM_addStyle
// @license MIT
// ==/UserScript==
(function () {
'use strict';
function translateAllTextNodes() {
const treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
let node;
while (node = treeWalker.nextNode()) {
translateNodeText(node);
}
}
function translateNodeText(node) {
if (node.parentNode.closest('materia-count-display, single-materia-view-only')) {
return;
}
let text = node.nodeValue;
for (const wordset of wordsets) {
for (const [key, value] of Object.entries(wordset)) {
text = text.replaceAll(key, value);
}
}
node.nodeValue = text;
}
const observer = new MutationObserver(() => {
translateAllTextNodes();
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
window.addEventListener('load', () => {
translateAllTextNodes();
});
GM_addStyle(`
materia-totals-display {
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
text-align: center !important;
margin-bottom: 1em;
padding: 0;
}
materia-count-display {
display: block !important;
margin-top: 4px;
text-align: center;
}
.materia-line-wrapper {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
margin-bottom: 4px;
white-space: nowrap;
}
.materia-stat-block-left {
display: flex;
align-items: center;
gap: 6px;
flex: 1;
}
.materia-name-quantity-right {
font-weight: bold;
text-align: right;
min-width: 120px;
white-space: nowrap;
flex-shrink: 0;
}
.materia-name-quantity {
white-space: nowrap;
}
.materia-stat-block {
display: flex;
align-items: center;
gap: 6px;
white-space: nowrap;
}
single-materia-view-only {
display: inline-block !important;
white-space: nowrap;
}
slot-materia-manager {
display: inline-flex !important;
align-items: center !important;
margin-right: 20px !important;
gap: 1px;
}
slot-materia-manager > .materia-image-holder {
flex-shrink: 0;
}
slot-materia-manager > span {
white-space: nowrap !important;
}
slot-materia-manager:last-child {
margin-right: 12 !important;
}
.gear-items-view-table th div {
white-space: nowrap;
overflow: visible;
}
`);
const wordReplacements = {
//기타2
"Math": "계산기",
"Solve for the highest-dps set of melds for this gearset.": "이 장비세트를 위한 최대 DPS 금단을 계산합니다. ",
"Computation will be much slower without a target GCD.": "글쿨 목표치를 설정하지 않으면 계산이 많이 느릴 것입니다.",
"Target GCD": "글쿨 목표치",
"New Gear Set": "새 장비세트",
"Add Simulation": "시뮬레이션 추가",
"Default Set": "기본 장비세트",
//스탯
"STR": "힘","Strength": "힘",
"DEX": "민첩","Dexterity": "민첩",
"VIT": "활력","Vitality": "활력",
"INT": "지능","Intelligence": "지능",
"MND": "정신력","Mind": "정신력",
"CRT": "극대화","Crit": "극대화",
"DET": "의지력","Determination": "의지력",
"DHT": "직격","DH": "직격","Direct Hit": "직격",
"MDEF": "마법 방어",
"DEF": "물리 방어",
"SkS": "기시속","SkS": "기시속","Skill Speed": "기시속",
"SpS": "마시속","SPS": "마시속","Spell Speed": "마시속",
"TNC": "불굴","Tenacity": "불굴",
"PIE": "신앙","Piety": "신앙",
"Main Stat": "주 능력치",
"WD": "공격력","Weapon Damage": "공격력",
"GCD": "글쿨",
"Levels": "레벨",
"Jobs": "직업","Job": "직업",
"Stat": "능력치",
"Multiplier": "계수",
"Dmg": "데미지",
"Def": "방어",
"PoM": "쾌속마",
"DoT": "도트",
//장비 슬롯
"Weapon:": "무기:",
"Head:": "머리:",
"Body:": "몸통:",
"Hand:": "손:",
"Legs:": "다리:",
"Feet:": "발:",
"Ears:": "귀:",
"Neck:": "목:",
"Wrist:": "손목:",
"Left Ring:": "왼쪽 손가락:",
"Right Ring:": "오른쪽 손가락:",
"Tome": "석판 장비",
" Raid": " 레이드 장비",
//방어구, 장신구 형용사 및 종류
"Augmented": "보강된","Aug.": "보강된",
"Quetzalli": "케츠할리",
"Dark Horse Champion's": "다크호스 챔피언",
"Ultimate Edenmorn": "절 에덴의 아침",
//방어구
"Helm of Fending": "수호자 투구","Bandana of Fending": "수호자 두건",
"Mail of Fending": "수호자 갑옷","Coat of Fending": "수호자 외투",
"Gauntlets of Fending": "수호자 건틀릿","Halfgloves of Fending": "수호자 손등장갑",
"Brais of Fending": "수호자 바지",
"Sollerets of Fending": "수호자 쇠구두","Greaves of Fending": "수호자 갑주장화",
"Helm of Maiming": "학살자 투구","Bandana of Maiming": "학살자 두건",
"Mail of Maiming": "학살자 갑옷","Coat of Maiming": "학살자 외투",
"Gauntlets of Maiming": "학살자 건틀릿","Halfgloves of Maiming": "학살자 손등장갑",
"Brais of Maiming": "학살자 바지","Breeches of Maiming": "학살자 바지",
"Sollerets of Maiming": "학살자 쇠구두","Greaves of Maiming": "학살자 갑주장화",
"Visor of Striking": "타격대 얼굴가리개","Hood of Striking": "타격대 후드",
"Jacket of Striking": "타격대 재킷","Coat of Striking": "타격대 외투",
"Vambraces of Striking": "타격대 완갑","Gloves of Striking": "타격대 장갑",
"Breeches of Striking": "타격대 바지","Brais of Striking": "타격대 바지",
"Leggings of Striking": "타격대 다리보호대","Boots of Striking": "타격대 장화",
"Visor of Aiming": "유격대 얼굴가리개","Mask of Aiming": "유격대 가면",
"Jacket of Aiming": "유격대 재킷",
"Vambraces of Aiming": "유격대 완갑","Gloves of Aiming": "유격대 장갑",
"Breeches of Aiming": "유격대 바지","Brais of Aiming": "유격대 바지",
"Leggings of Aiming": "유격대 다리보호대","Boots of Aiming": "유격대 장화",
"Visor of Scouting": "정찰대 얼굴가리개","Hood of Scouting": "정찰대 후드",
"Jacket of Scouting": "정찰대 재킷","Coat of Scouting": "정찰대 외투",
"Vambraces of Scouting": "정찰대 완갑","Gloves of Scouting": "정찰대 장갑",
"Breeches of Scouting": "정찰대 바지","Brais of Scouting": "정찰대 바지",
"Leggings of Scouting": "정찰대 다리보호대","Boots of Scouting": "정찰대 장화",
"Hood of Healing": "치유사 후드","Hat of Healing": "치유사 모자",
"Robe of Healing": "치유사 로브","Coat of Healing": "치유사 외투",
"Gloves of Healing": "치유사 장갑","Halfgloves of Healing": "치유사 손등장갑",
"Hose of Healing": "치유사 기마바지","Brais of Healing": "치유사 바지",
"Shoes of Healing": "치유사 신발",
"Hood of Casting": "마술사 후드","Hat of Casting": "마술사 모자",
"Robe of Casting": "마술사 로브","Coat of Casting": "마술사 외투",
"Gloves of Casting": "마술사 장갑","Halfgloves of Casting": "마술사 손등장갑",
"Hose of Casting": "마술사 기마바지","Brais of Casting": "마술사 바지",
"Shoes of Casting": "마술사 신발","Shoes of Casting": "마술사 신발",
//장신구
"Ear Cuffs of Fending": "수호자 귀찌","Earring of Fending": "수호자 귀걸이",
"Ear Cuffs of Slaying": "공격대 귀찌","Earring of Slaying": "공격대 귀걸이",
"Ear Cuffs of Aiming": "유격대 귀찌","Earring of Aiming": "유격대 귀걸이",
"Ear Cuffs of Healing": "치유사 귀찌","Earring of Healing": "치유사 귀걸이",
"Ear Cuffs of Casting": "마술사 귀찌","Earring of Casting": "마술사 귀걸이",
"Necklace of Fending": "수호자 목걸이","Choker of Fending": "수호자 목장식",
"Necklace of Slaying": "공격대 목걸이","Choker of Slaying": "공격대 목장식",
"Necklace of Aiming": "유격대 목걸이","Choker of Aiming": "유격대 목장식",
"Necklace of Healing": "치유사 목걸이","Choker of Healing": "치유사 목장식",
"Necklace of Casting": "마술사 목걸이","Choker of Casting": "마술사 목장식",
"Bracelets of Fending": "수호자 팔찌","Bangle of Fending": "수호자 장식고리",
"Bracelets of Slaying": "공격대 팔찌","Bangle of Slaying": "공격대 장식고리",
"Bracelets of Aiming": "유격대 팔찌","Bangle of Aiming": "유격대 장식고리",
"Bracelets of Healing": "치유사 팔찌","Bangle of Healing": "치유사 장식고리",
"Bracelets of Casting": "마술사 팔찌","Bangle of Casting": "마술사 장식고리",
"Ring of Fending": "수호자 반지",
"Ring of Slaying": "공격대 반지",
"Ring of Aiming": "유격대 반지",
"Ring of Healing": "치유사 반지",
"Ring of Casting": "마술사 반지",
//무기
"Longsword": "롱소드","Sword": "한손검",
"Patas": "파타","Jamadhars": "자마다르",
"Bardiche": "긴날도끼","Labrys": "양날도끼",
"Spear": "창","대체": "대체",
"Longbow": "장궁",
"Cane": "환술봉",
"Rod": "주술봉",
"Chronicle": "연대기","Index": "금서",
"Counsel": "상담록","Codex": "치유서",
"Knives": "단검",
"Greatsword": "그레이트소드",
"Handgonne": "권총","Musketoon": "단총",
"Star Globe": "천구의","Astrometer": "천체광도계",
"Samurai Blade": "외날검","Blade": "외날검",
"Rapier": "레이피어","Foil": "플뢰레",
"Bayonet": "총검","Gunblade": "건블레이드",
"Chakrams": "차크람","Tathlums": "타흘룸",
"War Scythe": "전투낫",
"Wings": "날개","Milpreves": "밀프레베",
"Twinfangs": "쌍송곳니",
"Round Brush": "둥근붓",
"Kite Shield": "연모양 방패",
//마테리아
"Quicktongue Mate": "시전의",
"Quickarm Mate": "신속의",
"Craftsman's Command Mate": "거장의",
"Craftsman's Cunning Mate": "명인의",
"Craftsman's Competence Mate": "장인의",
"Gatherer's Grasp Mate": "기량의",
"Gatherer's Guile Mate": "박식의",
"Gatherer's Guerdon Mate": "달견의",
"Battledance Mate": "강유의",
"Savage Might Mate": "야망의",
"Savage Aim Mate": "무략의",
"Heavens' Eye Mate": "심안의",
"Piety Mate": "신앙의",
"Mind Mate": "정신력의",
"Intelligence Mate": "지능의",
"Dexterity Mate": "민첩성의",
"Vitality Mate": "활력의",
"Strength Mate": "힘의",
"ria XII": " 하이알테마마테리쟈",
"ria XI": " 하이오메가마테리쟈",
"ria X": " 알테마마테리쟈",
"ria IX": " 오메가마테리쟈",
"ria VIII": " 엑스마테리쟈",
"ria VII": " 메가마테리쟈",
"ria VI": " 하이마테리쟈",
"ria V": " 마테리쟈",
"ria IV": " 마테리가",
"ria III": " 마테리다",
"ria II": " 마테리라",
"ria I": " 마테리아",
"Materia": "마테리아",
"Fill/Lock": "채우기/잠금",
"Mat": "마테",
"Solve Melds": "금단 계산",
"Meld": "금단",
"Solver": "계산기",
//음식
"Food": "음식",
"Moqueca": "무케카",
"Roast Chicken": "로스트 치킨",
"Churrasco": "슈하스코",
"Pineapple Orange Jelly": "파인애플 오렌지 젤리",
"Navel Orange Cookies": "배꼽 오렌지 쿠키",
//기타
"Totals:": "",
"No materia slots on this item": "마테리아 슬롯 없음",
"Alternative Items": "대체 가능 장비",
"Average Item Level": "평균 아이템 레벨",
"Set Name": "장비세트 이름",
"max": "최대",
"alt items": " 대체 가능 장비",
"The item ": "아이템 \"",
" can be replaced by all of the following items, which have equivalent or better effective stats:": "\"은(는) 아래의 장비로 대체 가능 합니다.",
"iLv": "아이템 레벨",
"To edit this sheet, click the \"Save As\" button below the table.": "이 시트를 수정하려면, 테이블 아래의 \"다른 이름으로 저장\" 버튼을 누르세요. ",
"Save As": "다른 이름으로 저장",
"Sheet Name": "시트 이름",
"Job:": "직업:",
"Level:": "레벨:",
"Sync Item Level": "아이템 레벨 조율",
"You don't have any sheets. Click 'New Sheet' to get started.": "시트가 없습니다. '새 시트'를 클릭해 시작합니다.",
"New Sheet": "새 시트",
"New Gear Planning Sheet": "새로운 장비 계획 시트",
"My Sheets": "내 시트",
"This is for importing gear set\\(s\\) into this sheet. ": "이 시트에 장비세트를 불러올 수 있습니다. ",
"If you would like to import a full sheet export \\(including sim settings\\) to a new sheet,": "시뮬레이터 설정을 포함해 내보냈었던 전체 시트를 불러오고 싶다면,",
"use the \"Import Sheet\" at the top of the page. You can import a gear planner URL or JSON, or an Etro URL.": "페이지 상단의 \"시트 불러오기\"를 사용하세요. 링크나 JSON, Etro 에서도 불러올 수 있습니다.",
"Import Sheet": "시트 불러오기",
"This will import into a new sheet. You can paste a gear planner link, gear planner JSON, or an Etro link.": "새 시트로 불러옵니다.",
"Import Sets": "장비세트 불러오기",
"Import Gear Set\\(s\\)": "장비세트 불러오기",
"Import": "불러오기",
"Export Full Sheet": "전체 시트 내보내기",
"Link to Whole Sheet": "전체 시트 링크",
"One Link for Each Set": "개별 장비세트 링크",
"Embed URL for Each Set": "개별 장비세트 임베드 URL",
"JSON for Whole Sheet": "전체 시트 JSON",
"Export Individual Set": "개별 장비세트 내보내기",
"Link to This Set": "선택한 세트 링크",
"JSON for This Set": "선택한 장비세트 JSON",
"Embed URL for This Set": "선택한 장비세트 임베드 URL",
"Export to Teamcraft": "전체 시트의 JSON",
"Choose Sims to Export": "내보낼 시뮬레이터 선택",
"Generate": "내보내기",
"Preview": "미리보기",
"Close": "닫기",
"Gear": "장비",
"Filters": "필터",
"Show NQ Items": "NQ 아이템 표시",
" Sim": " 시뮬",
"Sim:": "시뮬레이터:",
//"Export...": "내보내기...",
"Export Whole Sheet": "전체 시트 내보내기",
"Whole Sheet": "전체 시트",
"Selected Set": "선택한 세트",
"Toggle Header": "제목",
"Toggle Details": "자세히",
"Name": "이름",
"Source": "얻는 곳",
"Raid": "레이드",
"Ultimate": "절 레이드",
"Crafted": "제작",
"Unknown": "알 수 없음",
"Settings": "설정",
"Dark": "다크",
"Light": "라이트",
"Classic": "클래식",
"Modern": "모던",
"Game Items Language:": "게임 아이템 언어:",
"Meld Solver Workers:": "금단 계산기:",
//직업
"PLD": "나이트",
"WAR": "전사",
"DRK": "암흑기사",
"GNB": "건블레이드",
"WHM": "백마도사",
"SCH": "학자",
"AST": "점성술사",
"SGE": "현자",
"MNK": "몽크",
"DRG": "용기사",
"NIN": "닌자",
"SAM": "사무라이",
"RPR": "리퍼",
"VPR": "바이퍼",
"BRD": "음유시인",
"MCH": "기공사",
"DNC": "무도가",
"BLM": "흑마도사",
"SMN": "소환사",
"RDM": "적마도사",
"PCT": "픽토맨서",
"BLU": "청마도사",
//종족
"Select a Race/Clan": "종족/부족 선택",
"Duskwight": "황혼 부족",
"Wildwood": "숲 부족",
"Seekers of the Sun": "태양의 추종자",
"Keepers of the Moon": "달의 수호자",
"Sea Wolf": "바다늑대",
"Hellsguard": "불꽃지킴이",
"The Lost": "떠도는 별",
"Helion": "맴도는 별",
"Highlander": "고원 부족",
"Midlander": "중원 부족",
"Plainsfolk": "평원 부족",
"Dunesfolk": "사막 부족",
"Rava": "라바 비에라",
"Veena": "비나 비에라",
"Xaela": "아우라 젤라",
"Raen": "아우라 렌",
//파티 보너스
"No Party Bonus": "파티 보너스 없음",
"1 Unique Roles": "1종류 직업군",
"2 Unique Roles": "2종류 직업군",
"3 Unique Roles": "3종류 직업군",
"4 Unique Roles": "4종류 직업군",
"5 Unique Roles": "5종류 직업군",
};
function replaceText() {
const walk = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
let node;
while ((node = walk.nextNode())) {
let newText = node.nodeValue;
newText = newText.replace(/\+(\d+)\s+([가-힣]+)/g, (_, num, stat) => `${stat} +${num}`);
for (const [original, replacement] of Object.entries(wordReplacements)) {
newText = newText.replace(new RegExp(original, 'g'), replacement);
}
if (newText !== node.nodeValue) {
node.nodeValue = newText;
}
}
}
function updateMateriaLabels() {
const materiaDisplays = document.querySelectorAll('materia-count-display');
materiaDisplays.forEach(display => {
if (display.getAttribute('data-updated') === 'true') return;
const title = display.getAttribute('title');
if (!title) return;
const nameMatch = title.match(/^(.+?)\s*:/);
const statMatch = title.match(/:\s*\+(\d+)\s+(.+)$/);
if (!nameMatch || !statMatch) return;
const materiaName = nameMatch[1];
const statValue = statMatch[1];
const statNameOriginal = statMatch[2];
const quantityElem = display.querySelector('.materia-count-quantity');
const materiaView = display.querySelector('single-materia-view-only');
if (!quantityElem || !materiaView) return;
const quantityText = quantityElem.textContent.match(/\d+/)?.[0];
if (!quantityText) return;
const imageHolder = materiaView.querySelector('.materia-image-holder');
const statSpanInView = materiaView.querySelector('span');
const statText = statSpanInView?.textContent || `${statNameOriginal} +${statValue}`;
display.innerHTML = '';
const wrapper = document.createElement('div');
wrapper.className = 'materia-line-wrapper';
const statBlock = document.createElement('div');
statBlock.className = 'materia-stat-block-left';
if (materiaView && imageHolder) {
const clonedView = materiaView.cloneNode(true);
const holders = clonedView.querySelectorAll('.materia-image-holder');
const spans = clonedView.querySelectorAll('span');
holders.forEach((el, idx) => {
if (idx > 0) el.remove();
});
spans.forEach((el, idx) => {
if (idx > 0) el.remove();
});
statBlock.appendChild(clonedView);
}
const nameQuantitySpan = document.createElement('span');
nameQuantitySpan.className = 'materia-name-quantity-right';
nameQuantitySpan.textContent = `${materiaName} ${quantityText}개`;
const exportOption = document.querySelector('option[label="Export..."]');
if (exportOption) {
exportOption.label = '내보내기...';
}
wrapper.appendChild(statBlock);
wrapper.appendChild(nameQuantitySpan);
display.appendChild(wrapper);
display.setAttribute('data-updated', 'true');
});
}
window.addEventListener('load', () => {
replaceText();
updateMateriaLabels();
const observer = new MutationObserver(() => {
replaceText();
updateMateriaLabels();
});
observer.observe(document.body, {
childList: true,
subtree: true,
characterData: true
});
});
})();