mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Format code
This commit is contained in:
parent
dceebf05aa
commit
61b25eeedc
@ -1,158 +1,125 @@
|
|||||||
const languageCodeMap: { [key: string]: string } = {
|
const languageCodeMap: { [key: string]: string } = {
|
||||||
"日本語": "ja-JP",
|
"日本語": "ja-JP",
|
||||||
"English": "en-US",
|
"English": "en-US",
|
||||||
"Deutsch": "de-DE",
|
"Deutsch": "de-DE",
|
||||||
};
|
};
|
||||||
export class Translator
|
export class Translator {
|
||||||
{
|
static textNode: TextNodeTranslator;
|
||||||
static textNode: TextNodeTranslator;
|
static title: TitleTranslator;
|
||||||
static title: TitleTranslator;
|
static placeholder: PlaceholderTranslator;
|
||||||
static placeholder: PlaceholderTranslator;
|
static settingsDropdown: SettingsDropdownTranslator;
|
||||||
static settingsDropdown: SettingsDropdownTranslator;
|
static sensitiveTranslators: Translator[];
|
||||||
static sensitiveTranslators: Translator[];
|
static map: Map<string, any>;
|
||||||
static map: Map<string, any>;
|
static regex: [RegExp, string][];
|
||||||
static regex: [RegExp, string][];
|
|
||||||
|
|
||||||
accepts(node: Node) { return node.nodeType === Node.ELEMENT_NODE; }
|
accepts(node: Node) { return node.nodeType === Node.ELEMENT_NODE; }
|
||||||
getValue(node: Node) { return node.nodeValue; }
|
getValue(node: Node) { return node.nodeValue; }
|
||||||
setValue(node: Node, value: string) { node.nodeValue = value; }
|
setValue(node: Node, value: string) { node.nodeValue = value; }
|
||||||
getElement(node: Node) { return node as Element; }
|
getElement(node: Node) { return node as Element; }
|
||||||
translate(node: Node)
|
translate(node: Node) {
|
||||||
{
|
let value = this.getValue(node);
|
||||||
let value = this.getValue(node);
|
if (!value || typeof value !== "string" || value === "*") {
|
||||||
if (!value || typeof value !== "string" || value === "*")
|
return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
value = value.trim();
|
|
||||||
const translation = Translator.map.get(value);
|
|
||||||
if (translation === undefined)
|
|
||||||
{
|
|
||||||
const result = Translator.regex.find(([r]) => r.test(value!));
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
const [regex, replacement] = result;
|
|
||||||
this.setValue(node, value.replace(regex, replacement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (typeof translation === "string")
|
|
||||||
{
|
|
||||||
this.setValue(node, translation);
|
|
||||||
}
|
|
||||||
else if (Array.isArray(translation))
|
|
||||||
{
|
|
||||||
let finalTranslation = null;
|
|
||||||
for (const subTranslation of translation)
|
|
||||||
{
|
|
||||||
if (typeof subTranslation === "string")
|
|
||||||
{
|
|
||||||
finalTranslation = subTranslation;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const { text, selector, not } = subTranslation;
|
|
||||||
if (this.getElement(node).matches(selector) !== Boolean(not))
|
|
||||||
{
|
|
||||||
finalTranslation = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (finalTranslation !== null)
|
|
||||||
{
|
|
||||||
this.setValue(node, finalTranslation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const { text, selector, not } = translation;
|
|
||||||
if (this.getElement(node).matches(selector) !== Boolean(not))
|
|
||||||
{
|
|
||||||
this.setValue(node, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// https://stackoverflow.com/questions/10730309/find-all-text-nodes-in-html-page
|
value = value.trim();
|
||||||
static walk(rootElement: Node, action: (node: Node) => void)
|
const translation = Translator.map.get(value);
|
||||||
{
|
if (translation === undefined) {
|
||||||
const walker = document.createTreeWalker(rootElement, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, null, false);
|
const result = Translator.regex.find(([r]) => r.test(value!));
|
||||||
let node = walker.nextNode();
|
if (result) {
|
||||||
while (node)
|
const [regex, replacement] = result;
|
||||||
{
|
this.setValue(node, value.replace(regex, replacement));
|
||||||
action(node);
|
}
|
||||||
node = walker.nextNode();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
static translate(rootElement: Node)
|
else if (typeof translation === "string") {
|
||||||
{
|
this.setValue(node, translation);
|
||||||
if (rootElement.nodeType === Node.TEXT_NODE)
|
|
||||||
{
|
|
||||||
Translator.textNode.translate(rootElement);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const translateNode = (node: Node) =>
|
|
||||||
{
|
|
||||||
for (const translator of Translator.sensitiveTranslators)
|
|
||||||
{
|
|
||||||
if (translator.accepts(node))
|
|
||||||
{
|
|
||||||
translator.translate(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
translateNode(rootElement);
|
|
||||||
Translator.walk(rootElement, translateNode);
|
|
||||||
}
|
}
|
||||||
static translateCssMatches()
|
else if (Array.isArray(translation)) {
|
||||||
{
|
let finalTranslation = null;
|
||||||
const selectors = Translator.map.get("*");
|
for (const subTranslation of translation) {
|
||||||
if (!selectors)
|
if (typeof subTranslation === "string") {
|
||||||
{
|
finalTranslation = subTranslation;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
for (const { selector, text } of selectors)
|
else {
|
||||||
{
|
const { text, selector, not } = subTranslation;
|
||||||
const element = document.querySelector(selector);
|
if (this.getElement(node).matches(selector) !== Boolean(not)) {
|
||||||
if (element)
|
finalTranslation = text;
|
||||||
{
|
}
|
||||||
[...element.childNodes].filter(it => it.nodeType === Node.TEXT_NODE).forEach(it => it.nodeValue = text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (finalTranslation !== null) {
|
||||||
|
this.setValue(node, finalTranslation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
const { text, selector, not } = translation;
|
||||||
|
if (this.getElement(node).matches(selector) !== Boolean(not)) {
|
||||||
|
this.setValue(node, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// https://stackoverflow.com/questions/10730309/find-all-text-nodes-in-html-page
|
||||||
|
static walk(rootElement: Node, action: (node: Node) => void) {
|
||||||
|
const walker = document.createTreeWalker(rootElement, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, null, false);
|
||||||
|
let node = walker.nextNode();
|
||||||
|
while (node) {
|
||||||
|
action(node);
|
||||||
|
node = walker.nextNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static translate(rootElement: Node) {
|
||||||
|
if (rootElement.nodeType === Node.TEXT_NODE) {
|
||||||
|
Translator.textNode.translate(rootElement);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const translateNode = (node: Node) => {
|
||||||
|
for (const translator of Translator.sensitiveTranslators) {
|
||||||
|
if (translator.accepts(node)) {
|
||||||
|
translator.translate(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
translateNode(rootElement);
|
||||||
|
Translator.walk(rootElement, translateNode);
|
||||||
|
}
|
||||||
|
static translateCssMatches() {
|
||||||
|
const selectors = Translator.map.get("*");
|
||||||
|
if (!selectors) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const { selector, text } of selectors) {
|
||||||
|
const element = document.querySelector(selector);
|
||||||
|
if (element) {
|
||||||
|
[...element.childNodes].filter(it => it.nodeType === Node.TEXT_NODE).forEach(it => it.nodeValue = text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export class TextNodeTranslator extends Translator
|
export class TextNodeTranslator extends Translator {
|
||||||
{
|
accepts(node: Node) { return node.nodeType === Node.TEXT_NODE; }
|
||||||
accepts(node: Node) { return node.nodeType === Node.TEXT_NODE; }
|
getElement(node: Node) {
|
||||||
getElement(node: Node)
|
return node.parentElement!;
|
||||||
{
|
}
|
||||||
return node.parentElement!;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export class TitleTranslator extends Translator
|
export class TitleTranslator extends Translator {
|
||||||
{
|
getValue(node: Node) { return (node as Element).getAttribute("title"); }
|
||||||
getValue(node: Node) { return (node as Element).getAttribute("title"); }
|
setValue(node: Node, value: string) {
|
||||||
setValue(node: Node, value: string)
|
(node as Element).setAttribute("title", value);
|
||||||
{
|
}
|
||||||
(node as Element).setAttribute("title", value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export class PlaceholderTranslator extends Translator
|
export class PlaceholderTranslator extends Translator {
|
||||||
{
|
// accepts(node: Node) { return node.nodeName === "INPUT" && (node as HTMLInputElement).type.toUpperCase() === "TEXT" || node.nodeName === "TEXTAREA"; }
|
||||||
// accepts(node: Node) { return node.nodeName === "INPUT" && (node as HTMLInputElement).type.toUpperCase() === "TEXT" || node.nodeName === "TEXTAREA"; }
|
getValue(node: Node) { return (node as Element).getAttribute("placeholder"); }
|
||||||
getValue(node: Node) { return (node as Element).getAttribute("placeholder"); }
|
setValue(node: Node, value: string) {
|
||||||
setValue(node: Node, value: string)
|
(node as Element).setAttribute("placeholder", value);
|
||||||
{
|
}
|
||||||
(node as Element).setAttribute("placeholder", value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SettingsDropdownTranslator extends Translator
|
export class SettingsDropdownTranslator extends Translator {
|
||||||
{
|
accepts(node: Node) { return node instanceof HTMLInputElement && node.hasAttribute("key"); }
|
||||||
accepts(node: Node) { return node instanceof HTMLInputElement && node.hasAttribute("key"); }
|
getValue(node: Node) { return (node as HTMLInputElement).value; }
|
||||||
getValue(node: Node) { return (node as HTMLInputElement).value; }
|
setValue(node: Node, value: string) {
|
||||||
setValue(node: Node, value: string)
|
(node as HTMLInputElement).value = value;
|
||||||
{
|
}
|
||||||
(node as HTMLInputElement).value = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Translator.textNode = new TextNodeTranslator;
|
Translator.textNode = new TextNodeTranslator;
|
||||||
@ -161,53 +128,42 @@ Translator.placeholder = new PlaceholderTranslator;
|
|||||||
Translator.settingsDropdown = new SettingsDropdownTranslator;
|
Translator.settingsDropdown = new SettingsDropdownTranslator;
|
||||||
Translator.sensitiveTranslators = [Translator.textNode, Translator.title, Translator.placeholder];
|
Translator.sensitiveTranslators = [Translator.textNode, Translator.title, Translator.placeholder];
|
||||||
|
|
||||||
const startTranslate = async () =>
|
const startTranslate = async () => {
|
||||||
{
|
const languageCode = languageCodeMap[settings.i18nLanguage];
|
||||||
const languageCode = languageCodeMap[settings.i18nLanguage];
|
const { map, regex } = await import(`./i18n.${languageCode}`);
|
||||||
const { map, regex } = await import(`./i18n.${languageCode}`);
|
document.documentElement.setAttribute("lang", languageCode);
|
||||||
document.documentElement.setAttribute("lang", languageCode);
|
Translator.map = map as Map<string, any>;
|
||||||
Translator.map = map as Map<string, any>;
|
Translator.regex = [...regex.entries()] as Array<[RegExp, string]>;
|
||||||
Translator.regex = [...regex.entries()] as Array<[RegExp, string]>;
|
|
||||||
|
|
||||||
Translator.translate(document.body);
|
Translator.translate(document.body);
|
||||||
Translator.translateCssMatches();
|
Translator.translateCssMatches();
|
||||||
Observer.observe("body", records =>
|
Observer.observe("body", records => {
|
||||||
{
|
records.forEach(it => {
|
||||||
records.forEach(it =>
|
if (it.type === "childList") {
|
||||||
{
|
if (it.addedNodes.length > 0) {
|
||||||
if (it.type === "childList")
|
Translator.translateCssMatches();
|
||||||
{
|
}
|
||||||
if (it.addedNodes.length > 0)
|
it.addedNodes.forEach(node => {
|
||||||
{
|
Translator.translate(node);
|
||||||
Translator.translateCssMatches();
|
|
||||||
}
|
|
||||||
it.addedNodes.forEach(node =>
|
|
||||||
{
|
|
||||||
Translator.translate(node);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (it.type === "characterData")
|
|
||||||
{
|
|
||||||
Translator.textNode.translate(it.target);
|
|
||||||
}
|
|
||||||
else if (it.type === "attributes")
|
|
||||||
{
|
|
||||||
if (it.attributeName === "title")
|
|
||||||
{
|
|
||||||
Translator.title.translate(it.target);
|
|
||||||
}
|
|
||||||
else if (it.attributeName === "placeholder")
|
|
||||||
{
|
|
||||||
Translator.placeholder.translate(it.target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}, { characterData: true, childList: true, subtree: true, attributes: true });
|
}
|
||||||
const iconPanel = await SpinQuery.select(".gui-settings-icon-panel");
|
else if (it.type === "characterData") {
|
||||||
iconPanel!.addEventListener("be:load", () =>
|
Translator.textNode.translate(it.target);
|
||||||
{
|
}
|
||||||
Translator.walk(document.querySelector(".gui-settings-box")!, node => Translator.settingsDropdown.translate(node));
|
else if (it.type === "attributes") {
|
||||||
}, { once: true });
|
if (it.attributeName === "title") {
|
||||||
|
Translator.title.translate(it.target);
|
||||||
|
}
|
||||||
|
else if (it.attributeName === "placeholder") {
|
||||||
|
Translator.placeholder.translate(it.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, { characterData: true, childList: true, subtree: true, attributes: true });
|
||||||
|
const iconPanel = await SpinQuery.select(".gui-settings-icon-panel");
|
||||||
|
iconPanel!.addEventListener("be:load", () => {
|
||||||
|
Translator.walk(document.querySelector(".gui-settings-box")!, node => Translator.settingsDropdown.translate(node));
|
||||||
|
}, { once: true });
|
||||||
};
|
};
|
||||||
startTranslate();
|
startTranslate();
|
||||||
// if (document.readyState === "complete")
|
// if (document.readyState === "complete")
|
||||||
@ -220,15 +176,15 @@ startTranslate();
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
export: {
|
export: {
|
||||||
Translator,
|
Translator,
|
||||||
TextNodeTranslator,
|
TextNodeTranslator,
|
||||||
TitleTranslator,
|
TitleTranslator,
|
||||||
PlaceholderTranslator,
|
PlaceholderTranslator,
|
||||||
},
|
},
|
||||||
dropdown: {
|
dropdown: {
|
||||||
key: "i18nLanguage",
|
key: "i18nLanguage",
|
||||||
// items: Object.keys(languageCodeMap),
|
// items: Object.keys(languageCodeMap),
|
||||||
items: [`日本語`],
|
items: [`日本語`],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Loading…
Reference in New Issue
Block a user