// ==UserScript==
// @name OpenWF WebUI 管理/紫卡编辑器 - 自动补齐汉化
// @namespace http://tampermonkey.net/
// @version 20250829.094625
// @description 自动本地化所有动态内容和下拉框,支持页面刷新和内容变动
// @author vancat
// @match *://*/webui/*
// @match *://*/webui/inventory
// @match *://*/webui/mods
// @match *://*/webui/quests
// @match *://*/webui/cheats
// @match *://*/webui/import
// @match *://*/webui/riven-tool/*
// @icon https://5b0988e595225.cdn.sohucs.com/images/20171001/29f8b42081514b5ebef0e61c03547eb4.gif
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// 本地化映射, 按国服翻译优先
const localizationMap = {
'Buffs': '正面加成',
'Curses': '负面加成',
'Misc': '其他',
'Fingerprint': '印记代码',
'LotusArchgunRandomModRare': '空战武器',
'LotusModularMeleeRandomModRare': '天工武器',
'LotusModularPistolRandomModRare': '组件枪',
'LotusPistolRandomModRare': '副武器',
'LotusRifleRandomModRare': '步枪',
'LotusShotgunRandomModRare': '霰弹枪',
'PlayerMeleeWeaponRandomModRare': '近战',
'ArmorPiercingDamage': '穿刺伤害',
'CritChance': '暴击几率',
'CritDamage': '暴击伤害',
'ElectricityDamage': '电击伤害',
'FireDamage': '火焰伤害',
'FireRate': '射速/近战攻速',
'FreezeDamage': '冰冻伤害',
'ImpactDamage': '冲击伤害',
'ProcTime': '状态触发持续时间',
'SlashDamage': '切割伤害',
'StunChance': '状态触发几率',
'ToxinDamage': '毒素伤害',
'AmmoMax': '弹药最大值',
'ClipMax': '弹匣容量',
'DamageAmount': '基础伤害',
'FireIterations': '多重射击',
'PunctureDepth': '护甲穿透',
'RecoilReduction': '后坐力',
'ReloadSpeed': '装填速度',
'FactionDamageCorpus': '科普斯派系伤害',
'FactionDamageGrineer': '克隆尼派系伤害',
'FactionDamageInfested': '异变体派系伤害',
'ZoomFov': '缩放视野',
'MeleeDamage': '近战武器伤害',
'MeleeFactionDamageCorpus': '科普斯派系近战伤害',
'MeleeFactionDamageGrineer': '克隆尼派系近战伤害',
'MeleeFactionDamageInfested': '异变体派系近战伤害',
'ComboDuration': '连击持续时间',
'SlideAttackCritChance': '滑铲攻击暴击率',
'MeleeRangeInc': '近战范围',
'MeleeFinisherDamage': '近战终结伤害',
'MeleeComboEfficiency': '近战重击效率',
'MeleeComboInitialBonus': '近战初始连击',
'MeleeComboPointsOnHit': '近战命中获得连击数',
'MeleeComboBonusOnHit': '近战额外连击数几率',
'ProjectileSpeed': '投射物速度',
'Compat': '适用武器地址',
'Level': '等级',
'Polarity': '极性',
'Min MR': '最低段位要求',
'Rerolls': '洗卡次数',
'None': '无',
'Universal': '万用槽位',
'Vazarin': 'V极 (防御)',
'Naramon': 'N极 (辅助)',
'Madurai': 'V极 (伤害)',
'Zenurik': 'Z极 (战甲)',
'Unairu': 'U极 (架式)',
'Penjaga': 'Y极 (同伴)',
'Umbra': '暗影 (虚空)',
};
// 本地化的标签和类名
const elementTypesAndClasses = [
{ tag: 'P', classes: ['text'] },
{ tag: 'LABEL', classes: ['form-label'] },
{ tag: 'H5', classes: ['card-header'] },
{ tag: 'OPTION', classes: [] },
];
// 本地化单个元素
function localizeElement(element) {
if (!element || !element.textContent) return;
const originText = element.textContent.trim();
const localizedText = localizationMap[originText];
if (localizedText) {
element.textContent = localizedText;
}
}
// 本地化所有option
function localizeAllOptions(selectElement) {
if (!selectElement || !selectElement.options) return;
for (let option of selectElement.options) {
localizeElement(option);
}
}
// 初始化本地化所有已存在元素
function localizeInitialElements() {
elementTypesAndClasses.forEach(typeAndClass => {
const selector = typeAndClass.classes.length > 0
? `${typeAndClass.tag}.${typeAndClass.classes.join('.')}`
: typeAndClass.tag;
document.querySelectorAll(selector).forEach(el => {
if (typeAndClass.tag === 'SELECT') {
localizeAllOptions(el);
} else if (typeAndClass.tag === 'OPTION') {
localizeElement(el);
} else {
localizeElement(el);
}
});
});
// 额外处理所有select的option
document.querySelectorAll('select').forEach(localizeAllOptions);
}
// MutationObserver回调
function callback(mutationsList) {
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
// 递归本地化所有相关子元素
if (node.tagName === 'SELECT') {
localizeAllOptions(node);
} else if (node.tagName === 'OPTION') {
localizeElement(node);
} else {
elementTypesAndClasses.forEach(typeAndClass => {
if (node.tagName === typeAndClass.tag &&
(typeAndClass.classes.length === 0 || typeAndClass.classes.some(cls => node.classList.contains(cls)))) {
localizeElement(node);
}
});
}
// 递归处理子节点
node.querySelectorAll && node.querySelectorAll('option').forEach(localizeElement);
}
});
}
if (mutation.type === 'attributes') {
if (mutation.target.tagName === 'OPTION') {
localizeElement(mutation.target);
}
if (mutation.target.tagName === 'SELECT') {
localizeAllOptions(mutation.target);
}
}
}
}
// 启动观察器
const observer = new MutationObserver(callback);
observer.observe(document.body, { childList: true, subtree: true, attributes: true });
// 页面初始本地化
localizeInitialElements();
// 下拉框选项切换时本地化(全局处理所有select)
document.addEventListener('change', function (e) {
if (e.target && e.target.tagName === 'SELECT') {
const selectedOption = e.target.options[e.target.selectedIndex];
localizeElement(selectedOption);
}
});
// 页面完全加载后再本地化一次,防止异步渲染遗漏
window.addEventListener('DOMContentLoaded', localizeInitialElements);
})();