sd-webui-bilingual-localiza.../javascript/bilingual_localization.js

201 lines
4.8 KiB
JavaScript

(function () {
const customCSS = `
.bilingual__trans_wrapper {
display: flex;
flex-direction: column;
align-items: center;
font-size: 12px;
line-height: 1;
}
.bilingual__trans_wrapper em {
font-size: 12px;
font-style: normal;
}
.custom_ui__prompt_trans {
font-size: 12px;
}
#settings .bilingual__trans_wrapper,
label>span>.bilingual__trans_wrapper,
.w-full>span>.bilingual__trans_wrapper {
align-items: flex-start;
}
textarea::placeholder {
font-size: 12px;
line-height: 1;
padding: 5px 0;
}
label>span {
line-height: 1;
}
div[data-testid="image"]>div>div.touch-none>div {
background-color: rgba(255, 255, 255, .6);
color: #222;
}`
let i18n = null, config = null;
function setup() {
config = {
enabled: opts["bilingual_localization_enabled"],
file: opts["bilingual_localization_file"],
dirs: opts["bilingual_localization_dirs"],
order: opts["bilingual_localization_order"]
}
let { enabled, file, dirs } = config
if (!enabled || file === "None" || dirs === "None") return
dirs = JSON.parse(dirs)
// Load localization file
i18n = JSON.parse(readFile(dirs[file]))
}
// Translate page
function translatePage() {
if (!i18n) return
querySelectorAll(`
label span, fieldset span, thead th, th span, button,
textarea[placeholder], select[title], option,
.transition > div > span:not([class]),
.tabitem .pointer-events-none,
.output-html, #lightboxModal span
`)
.forEach(el => translateEl(el))
querySelectorAll(`
.output-html:not(#footer) p,
.output-html tabel:not(#extensions),
div[data-testid="image"] > div > div,
#extras_image_batch > div,
.extension-tag
`)
.forEach(el => translateEl(el, true))
}
// Translate element
function translateEl(el, deep) {
if (el.className === 'bilingual__trans_wrapper') return
if (deep) {
Array.from(el.childNodes).forEach(node => {
if (node.nodeName === '#text') {
doTranslate(node, node.textContent, 'node')
} else if (node.childNodes.length > 0) {
translateEl(node, true)
}
})
return
}
if (el.textContent && el.tagName !== 'SELECT') {
if (el.tagName === 'OPTION') {
doTranslate(el, el.textContent, 'option')
} else {
doTranslate(el, el.textContent, 'element')
}
}
if (el.title) {
doTranslate(el, el.title, 'title')
}
if (el.placeholder) {
doTranslate(el, el.placeholder, 'placeholder')
}
}
function doTranslate(el, source, type) {
source = source.trim()
if (!source) return
let translation = i18n[source]
if (!translation) return
if (source === translation) return
if (config.order === "Original First") {
[source, translation] = [translation, source]
}
switch (type) {
case 'node':
el.textContent = translation
break;
case 'element':
if (el.childNodes.length === 1 || !el.classList.contains('pointer-events-none')) {
el.innerHTML = `<div class="bilingual__trans_wrapper"><em>${translation}</em>${source}</div>`
} else {
const textNode = Array.from(el.childNodes).find(node => node.nodeName === '#text' && node.textContent.trim() === source)
textNode && (textNode.textContent = `${translation} (${source})`)
}
break;
case 'option':
el.textContent = `${translation} (${source})`
break;
case 'title':
el.title = `${translation}\n${source}`
break;
case 'placeholder':
el.placeholder = `${translation}\n\n${source}`
break;
}
}
function querySelector(...args) {
return gradioApp()?.querySelector(...args)
}
function querySelectorAll(...args) {
return gradioApp()?.querySelectorAll(...args)
}
// Load file
function readFile(filePath) {
let request = new XMLHttpRequest();
request.open("GET", `file=${filePath}`, false);
request.send(null);
return request.responseText;
}
function init() {
// Add style to dom
let $styleEL = document.createElement('style');
if ($styleEL.styleSheet) {
$styleEL.styleSheet.cssText = customCSS;
} else {
$styleEL.appendChild(document.createTextNode(customCSS));
}
gradioApp().appendChild($styleEL);
let loaded = false
onUiUpdate(() => {
translatePage()
if (loaded) return
if (Object.keys(localization).length) return
if (Object.keys(opts).length === 0) return;
if (i18n) return;
loaded = true
setup()
})
}
// Init after page loaded
document.addEventListener('DOMContentLoaded', init)
})();