跳转到内容

MediaWiki:Gadget-interfaceVariantConverter.js:修订间差异

来自萌娘共享
代码变动:a157f65a - chore by U:星海子
标签由机器人或全自动脚本执行的操作
代码变动:a157f65a - chore by U:星海子
标签由机器人或全自动脚本执行的操作
第8行: 第8行:
/* <pre> */
/* <pre> */


"use strict";
"use strict";$(()=>(async()=>{var t,e;const i=mw.config.get("wgPageName"),n=mw.config.get("wgUserName"),s=mw.config.get("wgArticleId"),o=i.replace(/\/.*?$/,""),a=new mw.Api,r=/m?zh\.moegirl\.org\.cn/.test(location.hostname)?a:new mw.ForeignApi("https://mzh.moegirl.org.cn/api.php",{anonymous:!0}),c=$.extend({main:["zh-cn","zh-tw","zh-hk"],dependent:{"(main)":"zh-cn","zh-hans":"zh-cn","zh-hant":"zh-tw"},noteTA:{G1:"MediaWiki"},autoPopulate:!0,useOpenCC:!0,manualAction:{"zh-hk":t=>t.replaceAll("户","戶"),"zh-tw":t=>t.replaceAll("名稱空間","命名空間").replaceAll("記憶體","內存")},watchlist:"nochange"},window.lr_aivc);let h="";try{h=c.autoPopulate?(await a.get({action:"parse",assertuser:n,pageid:s,prop:"wikitext"})).parse.wikitext["*"]:""}catch{}const variantPage=t=>"(main)"===t?`${o}`:`${o}/${t}`,w=/-{([\s\S]*?)}-/g,l=/-\\{([\s\S]*?)}\\-/g,O=/<nowiki>([\s\S]*?)<\/nowiki>/g,g=/\[\[([\s\S]*?)(?:#([\s\S]*?))?(\|[\s\S]*?)?\]\]/g,p=/([^[])\[([^[]+?)( [\s\S]+?)?\]([^\]])/g,d=/\{\{([\s\S]*?)\}\}/g,m=/&([a-zA-Z0-9#]+);/g,u=/<!--noOCC-->([\s\S]*?)<!--\/noOCC-->/gi,restoreWikitext=(t,e)=>{const i=[];let n=t;return n=n.replace(O,(t,e)=>`<nowiki>${i.push(e)-1}</nowiki>`),n=n.replace(m,(t,i)=>`&${e[i]};`),n=n.replace(d,(t,i)=>{const n=i.split("|"),s=e[n[0]];return n.shift(),`${n.reduce((t,i)=>{const[n,...s]=i.split("=");return s.length?`${t}|${e[n]}=${s.join("=")}`:`${t}|${i}`},`{{${s}`)}}}`}),n=n.replace(p,(t,i,n,s,o)=>`${i}[${e[n]}${s||""}]${o}`),n=n.replace(g,(t,i,n,s)=>n||s?`[[${s?e[i]:i}${e[n]?`#${e[n]}`:""}${s||""}]]`:t),n=n.replace(O,(t,e)=>`<nowiki>${i[e]}</nowiki>`),n=n.replace(l,(t,i)=>`-{${e[i]??i}}-`),n};class AIVCWindow extends(e=OO.ui.ProcessDialog){constructor(t){super(t),this.config=t.data.config,this.prepopContent=t.data.prepopContent}initialize(){super.initialize(),this.configPanel=new OO.ui.PanelLayout({scrollable:!1,expanded:!1,padded:!0}),this.confirmPanel=new OO.ui.PanelLayout({scrollable:!1,expanded:!1,padded:!0}),this.ogText=new OO.ui.MultilineTextInputWidget({value:this.prepopContent,autosize:!0});const t=new OO.ui.FieldLayout(this.ogText,{label:wgULS("原始内容","原始內容"),align:"top"});this.mainVariants=new OO.ui.TextInputWidget({value:this.config.main.join(";")});const e=new OO.ui.FieldLayout(this.mainVariants,{label:wgULS("主要变体","主要變体"),align:"top"});this.depVariants=new OO.ui.TextInputWidget({value:Object.entries(this.config.dependent).map(([t,e])=>`${t}:${e}`).join(";")});const i=new OO.ui.FieldLayout(this.depVariants,{label:wgULS("依赖变体","依賴變体"),align:"top"});var n;this.noteTAParams=new OO.ui.TextInputWidget({value:(n=this.config.noteTA,Object.entries(n).map(([t,e])=>`${t}=${e}`).join("|"))});const s=new OO.ui.FieldLayout(this.noteTAParams,{label:wgULS("NoteTA参数","NoteTA參數"),align:"top"});this.occCheckbox=new OO.ui.CheckboxInputWidget({selected:this.config.useOpenCC});const o=new OO.ui.FieldLayout(this.occCheckbox,{label:"使用OpenCC",align:"inline"});this.configPanel.$element.append(t.$element,e.$element,i.$element,s.$element,o.$element),this.stackLayout=new OO.ui.StackLayout({items:[this.configPanel,this.confirmPanel]}),this.ogText.connect(this,{resize:"updateSize"}),this.$body.append(this.stackLayout.$element)}getBodyHeight(){return this.stackLayout.getCurrentItem().$element.outerHeight(!0)}getSetupProcess(t){return super.getSetupProcess(t).next(()=>{this.actions.setMode("config"),this.stackLayout.setItem(this.configPanel)},this)}getReadyProcess(t){return super.getReadyProcess(t).next(()=>{this.ogText.focus()},this)}getActionProcess(t){if("cancel"===t)return new OO.ui.Process(()=>{this.close({action:t})},this);if("continue"===t)return new OO.ui.Process($.when((async()=>{if(this.config=$.extend(this.config,{main:this.mainVariants.getValue().split(";"),dependent:Object.fromEntries(this.depVariants.getValue().split(";").map(t=>t.split(":"))),noteTAStr:this.noteTAParams.getValue(),useOpenCC:this.occCheckbox.isSelected(),dependentInv:{}}),this.config.main.includes("(main)"))throw new OO.ui.Error(wgULS("主页面不得作为主要变体","主頁面不得作為主要變体"));this.config.main.forEach(t=>this.config.dependentInv[t]=[t]);try{Object.entries(this.config.dependent).forEach(([t,e])=>this.config.dependentInv[e].push(t))}catch{throw console.error("[VariantConverter] Error: Key not found in dependentInv. Config dump:",this.config),new OO.ui.Error(wgULS("依赖变体格式错误,请检查控制台","依賴變体格式錯誤,請檢查控制臺"))}this.textInputs={},this.confirmPanel.$element.empty();try{await this.getVariants(this.ogText.getValue()),this.actions.setMode("confirm"),this.stackLayout.setItem(this.confirmPanel),this.updateSize()}catch(t){throw console.error("[VariantConverter] Error:",t),new OO.ui.Error(t)}})()).promise(),this);if("back"===t)this.actions.setMode("config"),this.stackLayout.setItem(this.configPanel),this.updateSize();else if("submit"===t)return new OO.ui.Process($.when((async()=>{try{await this.saveChanges(),this.close({action:t}),mw.notify("保存成功!",{title:wgULS("自动繁简转换工具","自動繁簡轉換工具"),type:"success",tag:"lr-aivc"}),setTimeout(()=>location.reload(),730)}catch(t){throw console.error("[VariantConverter] Error:",t),new OO.ui.Error(t)}})()).promise(),this);return super.getActionProcess(t)}addVariant(t,e){this.textInputs[t]=new OO.ui.MultilineTextInputWidget({value:e,autosize:!0});const i=new OO.ui.FieldLayout(this.textInputs[t],{label:t,align:"top"});this.textInputs[t].connect(this,{resize:"updateSize"}),this.confirmPanel.$element.append(i.$element),window?.InPageEdit?.quickDiff&&this.confirmPanel.$element.append(new OO.ui.FieldLayout(new OO.ui.Widget({content:[new OO.ui.HorizontalLayout({items:this.config.dependentInv[t].map(e=>new OO.ui.ButtonWidget({label:`${wgULS("对比","對比")}${"(main)"===e?wgULS("主页面","主頁面"):e}`}).on("click",()=>window.InPageEdit.quickDiff({fromtitle:variantPage(e),totext:this.textInputs[t].getValue(),pageName:variantPage(e),isPreview:!0})))})]})).$element)}async getVariants(t){this.confirmPanel.$element.append(`<p>${wgULS("请确认以下转换是否正确","請確認以下轉換是否正確")}:</p>`),!window.OpenCC&&this.config.useOpenCC&&await libCachedCode.injectCachedCode("https://npm.elemecdn.com/opencc-js@latest","script");const{replaced:e,mappings:i}=(t=>{const e=[],i=[];let n=t;return n=n.replace(w,(t,e)=>`-\\{${e}}\\-`),n=n.replace(O,(t,i)=>`<nowiki>${e.push(i)-1}</nowiki>`),n=n.replace(g,(t,e,n,s)=>n||s?`[[${s?i.push(e)-1:e}${n?"#"+(i.push(n)-1):""}${s||""}]]`:t),n=n.replace(p,(t,e,n,s,o)=>`${e}[${i.push(n)-1}${s||""}]${o}`),n=n.replace(d,(t,e)=>{const n=e.split("|");return i.push(n[0]),n.shift(),`${n.reduce((t,e)=>{const[n,...s]=e.split("=");return s.length?`${t}|${i.push(n)-1}=${s.join("=")}`:`${t}|${e}`},"{{"+(i.length-1))}}}`}),n=n.replace(l,(t,e)=>`-\\{${i.push(e||"")-1}}\\-`),n=n.replace(m,(t,e)=>`&${i.push(e)-1};`),n=n.replace(O,(t,i)=>`<nowiki><nowiki>${e[i]}</nowiki></nowiki>`),{replaced:n,mappings:i}})(t);for(const t of this.config.main){if("(main)"===t)continue;const s=`{{NoteTA|${this.config.noteTAStr}}}<pre id="converted">-{}-${e}</pre>`;let o=$($.parseHTML((await r.post({action:"parse",assertuser:n,text:s,contentmodel:"wikitext",prop:"text",uselang:t,disablelimitreport:!0,pst:!0})).parse.text["*"])).find("#converted").text();if(this.config.useOpenCC){const e=[];o=o.replace(u,(t,i)=>`\x3c!--noOCC--\x3e${e.push(i)-1}\x3c!--/noOCC--\x3e`);const i=t.replace("hans","cn").replace(/zh-(?:han)?/,"").replace("tw","twp");o=OpenCC.Converter({from:i,to:i})(o),o=o.replace(u,(t,i)=>`\x3c!--noOCC--\x3e${e[i]}\x3c!--/noOCC--\x3e`)}const a=this.config.manualAction[t]?.(o)||o,c=restoreWikitext(a,i);this.addVariant(t,c)}}async saveChanges(){console.log("[VariantConverter] Saved changes",await Promise.allSettled(this.config.main.map(t=>{const e=this.textInputs[t].getValue();return a.postWithToken("csrf",{action:"edit",assertuser:n,title:variantPage(t),text:e,summary:`自动转换自[[${i}]]`,tags:"VariantConverter|Automation tool",watchlist:this.config.watchlist})}).concat(Object.entries(this.config.dependent).map(([t,e])=>{const s=this.textInputs[e].getValue();return a.postWithToken("csrf",{action:"edit",assertuser:n,title:variantPage(t),text:s,summary:`自动转换自[[${i}]](同步${e})`,tags:"VariantConverter|Automation tool",watchlist:this.config.watchlist})}))))}}t=AIVCWindow,AIVCWindow.static={...Reflect.get(e,"static",t),tagName:"div",name:"lr-aivc",title:wgULS("自动繁简转换工具","自動繁簡轉換工具"),actions:[{action:"cancel",label:"取消",flags:["safe","close","destructive"],modes:"config"},{action:"continue",label:wgULS("继续","繼續"),flags:["primary","progressive"],modes:"config"},{action:"back",label:"返回",flags:["safe","back"],modes:"confirm"},{action:"submit",label:wgULS("确认","確認"),flags:["primary","progressive"],modes:"confirm"}]};const C=$(document.body),f=new OO.ui.WindowManager;C.append(f.$element);const S=new AIVCWindow({size:"large",data:{config:c,prepopContent:h}});f.addWindows([S]),$(mw.util.addPortletLink("p-cactions","#",wgULS("自动繁简转换","自動繁簡轉換"),"ca-VariantConverter",wgULS("自动同步界面消息的繁简版本","自動同步介面消息的繁簡版本"))).on("click",t=>{t.preventDefault(),$("#mw-notification-area").appendTo(C),f.openWindow(S)})})());  
$(() => (async () => {
    var _a, _b;
    const pagename = mw.config.get("wgPageName");
    const username = mw.config.get("wgUserName");
    const pageid = mw.config.get("wgArticleId");
    const basepage = pagename.replace(/\/.*?$/, "");
    const api = new mw.Api(), zhAPI = /m?zh\.moegirl\.org\.cn/.test(location.hostname) ? api : new mw.ForeignApi("https://mzh.moegirl.org.cn/api.php", { anonymous: true });
    const lrAivc = $.extend({
        main: ["zh-cn", "zh-tw", "zh-hk"],
        dependent: {
            "(main)": "zh-cn",
            "zh-hans": "zh-cn",
            "zh-hant": "zh-tw",
        },
        noteTA: {
            G1: "MediaWiki",
        },
        autoPopulate: true,
        useOpenCC: true,
        manualAction: {
            "zh-hk": (t) => t.replaceAll("户", "戶"),
            "zh-tw": (t) => t.replaceAll("名稱空間", "命名空間").replaceAll("記憶體", "內存"),
        },
        watchlist: "nochange",
    }, window.lr_aivc);
    let prepopContent = "";
    try {
        prepopContent = lrAivc.autoPopulate
            ? (await api.get({
                action: "parse",
                assertuser: username,
                pageid,
                prop: "wikitext",
            })).parse.wikitext["*"]
            : "";
    }
    catch { }
    const toParams = (obj) => Object.entries(obj).map(([k, v]) => `${k}=${v}`).join("|");
    const variantPage = (variant) => variant === "(main)" ? `${basepage}` : `${basepage}/${variant}`;
    const REGEXP = {
        lcMarker: /-{([\s\S]*?)}-/g,
        lcMarkerEsc: /-\\{([\s\S]*?)}\\-/g,
        nowiki: /<nowiki>([\s\S]*?)<\/nowiki>/g,
        link: /\[\[([\s\S]*?)(?:#([\s\S]*?))?(\|[\s\S]*?)?\]\]/g,
        extLink: /([^[])\[([^[]+?)( [\s\S]+?)?\]([^\]])/g,
        template: /\{\{([\s\S]*?)\}\}/g,
        htmlEntity: /&([a-zA-Z0-9#]+);/g,
        noOCC: /<!--noOCC-->([\s\S]*?)<!--\/noOCC-->/gi,
    };
    const escapeWikitext = (original) => {
        const nowikis = [], mappings = [];
        let replaced = original;
        replaced = replaced.replace(REGEXP.lcMarker, (_, content) => `-\\{${content}}\\-`);
        replaced = replaced.replace(REGEXP.nowiki, (_, content) => `<nowiki>${nowikis.push(content) - 1}</nowiki>`);
        replaced = replaced.replace(REGEXP.link, (match, target, anchor, text) => anchor || text ? `[[${text ? mappings.push(target) - 1 : target}${anchor ? `#${mappings.push(anchor) - 1}` : ""}${text || ""}]]` : match);
        replaced = replaced.replace(REGEXP.extLink, (_, before, target, text, after) => `${before}[${mappings.push(target) - 1}${text || ""}]${after}`);
        replaced = replaced.replace(REGEXP.template, (_, params) => {
            const paramList = params.split("|");
            mappings.push(paramList[0]);
            paramList.shift();
            return `${paramList.reduce((acc, param) => {
                const [first, ...rest] = param.split("=");
                return rest.length ? `${acc}|${mappings.push(first) - 1}=${rest.join("=")}` : `${acc}|${param}`;
            }, `{{${mappings.length - 1}`)}}}`;
        });
        replaced = replaced.replace(REGEXP.lcMarkerEsc, (_, content) => `-\\{${mappings.push(content || "") - 1}}\\-`);
        replaced = replaced.replace(REGEXP.htmlEntity, (_, entity) => `&${mappings.push(entity) - 1};`);
        replaced = replaced.replace(REGEXP.nowiki, (_, index) => `<nowiki><nowiki>${nowikis[index]}</nowiki></nowiki>`);
        return { replaced, mappings };
    };
    const restoreWikitext = (original, mappings) => {
        const nowikis = [];
        let replaced = original;
        replaced = replaced.replace(REGEXP.nowiki, (_, content) => `<nowiki>${nowikis.push(content) - 1}</nowiki>`);
        replaced = replaced.replace(REGEXP.htmlEntity, (_, index) => `&${mappings[index]};`);
        replaced = replaced.replace(REGEXP.template, (_, params) => {
            const paramList = params.split("|");
            const name = mappings[paramList[0]];
            paramList.shift();
            return `${paramList.reduce((acc, param) => {
                const [first, ...rest] = param.split("=");
                return rest.length ? `${acc}|${mappings[first]}=${rest.join("=")}` : `${acc}|${param}`;
            }, `{{${name}`)}}}`;
        });
        replaced = replaced.replace(REGEXP.extLink, (_, before, target, text, after) => `${before}[${mappings[target]}${text || ""}]${after}`);
        replaced = replaced.replace(REGEXP.link, (match, target, anchor, text) => anchor || text ? `[[${text ? mappings[target] : target}${mappings[anchor] ? `#${mappings[anchor]}` : ""}${text || ""}]]` : match);
        replaced = replaced.replace(REGEXP.nowiki, (_, index) => `<nowiki>${nowikis[index]}</nowiki>`);
        replaced = replaced.replace(REGEXP.lcMarkerEsc, (_, index) => `-{${mappings[index] ?? index}}-`);
        return replaced;
    };
    class AIVCWindow extends (_b = OO.ui.ProcessDialog) {
        constructor(config) {
            super(config);
            this.config = config.data.config;
            this.prepopContent = config.data.prepopContent;
        }
        initialize() {
            super.initialize();
            this.configPanel = new OO.ui.PanelLayout({
                scrollable: false,
                expanded: false,
                padded: true,
            });
            this.confirmPanel = new OO.ui.PanelLayout({
                scrollable: false,
                expanded: false,
                padded: true,
            });
            this.ogText = new OO.ui.MultilineTextInputWidget({
                value: this.prepopContent,
                autosize: true,
            });
            const textField = new OO.ui.FieldLayout(this.ogText, {
                label: wgULS("原始内容", "原始內容"),
                align: "top",
            });
            this.mainVariants = new OO.ui.TextInputWidget({
                value: this.config.main.join(";"),
            });
            const mainField = new OO.ui.FieldLayout(this.mainVariants, {
                label: wgULS("主要变体", "主要變体"),
                align: "top",
            });
            this.depVariants = new OO.ui.TextInputWidget({
                value: Object.entries(this.config.dependent).map(([k, v]) => `${k}:${v}`).join(";"),
            });
            const depField = new OO.ui.FieldLayout(this.depVariants, {
                label: wgULS("依赖变体", "依賴變体"),
                align: "top",
            });
            this.noteTAParams = new OO.ui.TextInputWidget({
                value: toParams(this.config.noteTA),
            });
            const noteTAField = new OO.ui.FieldLayout(this.noteTAParams, {
                label: wgULS("NoteTA参数", "NoteTA參數"),
                align: "top",
            });
            this.occCheckbox = new OO.ui.CheckboxInputWidget({
                selected: this.config.useOpenCC,
            });
            const occField = new OO.ui.FieldLayout(this.occCheckbox, {
                label: "使用OpenCC",
                align: "inline",
            });
            this.configPanel.$element.append(textField.$element, mainField.$element, depField.$element, noteTAField.$element, occField.$element);
            this.stackLayout = new OO.ui.StackLayout({
                items: [this.configPanel, this.confirmPanel],
            });
            this.ogText.connect(this, { resize: "updateSize" });
            this.$body.append(this.stackLayout.$element);
        }
        getBodyHeight() {
            return this.stackLayout.getCurrentItem().$element.outerHeight(true);
        }
        getSetupProcess(data) {
            return super.getSetupProcess(data).next(() => {
                this.actions.setMode("config");
                this.stackLayout.setItem(this.configPanel);
            }, this);
        }
        getReadyProcess(data) {
            return super.getReadyProcess(data)
                .next(() => {
                this.ogText.focus();
            }, this);
        }
        getActionProcess(action) {
            if (action === "cancel") {
                return new OO.ui.Process(() => {
                    this.close({ action: action });
                }, this);
            }
            else if (action === "continue") {
                return new OO.ui.Process($.when((async () => {
                    this.config = $.extend(this.config, {
                        main: this.mainVariants.getValue().split(";"),
                        dependent: Object.fromEntries(this.depVariants.getValue().split(";").map((v) => v.split(":"))),
                        noteTAStr: this.noteTAParams.getValue(),
                        useOpenCC: this.occCheckbox.isSelected(),
                        dependentInv: {},
                    });
                    if (this.config.main.includes("(main)")) {
                        throw new OO.ui.Error(wgULS("主页面不得作为主要变体", "主頁面不得作為主要變体"));
                    }
                    this.config.main.forEach((v) => this.config.dependentInv[v] = [v]);
                    try {
                        Object.entries(this.config.dependent).forEach(([k, v]) => this.config.dependentInv[v].push(k));
                    }
                    catch {
                        console.error("[VariantConverter] Error: Key not found in dependentInv. Config dump:", this.config);
                        throw new OO.ui.Error(wgULS("依赖变体格式错误,请检查控制台", "依賴變体格式錯誤,請檢查控制臺"));
                    }
                    this.textInputs = {};
                    this.confirmPanel.$element.empty();
                    try {
                        await this.getVariants(this.ogText.getValue());
                        this.actions.setMode("confirm");
                        this.stackLayout.setItem(this.confirmPanel);
                        this.updateSize();
                    }
                    catch (e) {
                        console.error("[VariantConverter] Error:", e);
                        throw new OO.ui.Error(e);
                    }
                })()).promise(), this);
            }
            else if (action === "back") {
                this.actions.setMode("config");
                this.stackLayout.setItem(this.configPanel);
                this.updateSize();
            }
            else if (action === "submit") {
                return new OO.ui.Process($.when((async () => {
                    try {
                        await this.saveChanges();
                        this.close({ action: action });
                        mw.notify("保存成功!", {
                            title: wgULS("自动繁简转换工具", "自動繁簡轉換工具"),
                            type: "success",
                            tag: "lr-aivc",
                        });
                        setTimeout(() => location.reload(), 730);
                    }
                    catch (e) {
                        console.error("[VariantConverter] Error:", e);
                        throw new OO.ui.Error(e);
                    }
                })()).promise(), this);
            }
            return super.getActionProcess(action);
        }
        addVariant(variant, text) {
            this.textInputs[variant] = new OO.ui.MultilineTextInputWidget({
                value: text,
                autosize: true,
            });
            const field = new OO.ui.FieldLayout(this.textInputs[variant], {
                label: variant,
                align: "top",
            });
            this.textInputs[variant].connect(this, { resize: "updateSize" });
            this.confirmPanel.$element.append(field.$element);
            if (window?.InPageEdit?.quickDiff) {
                this.confirmPanel.$element.append(new OO.ui.FieldLayout(new OO.ui.Widget({
                    content: [
                        new OO.ui.HorizontalLayout({
                            items: this.config.dependentInv[variant].map((v) => new OO.ui.ButtonWidget({
                                label: `${wgULS("对比", "對比")}${v === "(main)" ? wgULS("主页面", "主頁面") : v}`,
                            }).on("click", () => window.InPageEdit.quickDiff({
                                fromtitle: variantPage(v),
                                totext: this.textInputs[variant].getValue(),
                                pageName: variantPage(v),
                                isPreview: true,
                            }))),
                        }),
                    ],
                })).$element);
            }
        }
        async getVariants(original) {
            this.confirmPanel.$element.append(`<p>${wgULS("请确认以下转换是否正确", "請確認以下轉換是否正確")}:</p>`);
            if (!window.OpenCC && this.config.useOpenCC) {
                await libCachedCode.injectCachedCode("https://npm.elemecdn.com/opencc-js@latest", "script");
            }
            const { replaced, mappings } = escapeWikitext(original);
            for (const variant of this.config.main) {
                if (variant === "(main)") {
                    continue;
                }
                const text = `{{NoteTA|${this.config.noteTAStr}}}<pre id="converted">-{}-${replaced}</pre>`;
                const parsed = $($.parseHTML((await zhAPI.post({
                    action: "parse",
                    assertuser: username,
                    text,
                    contentmodel: "wikitext",
                    prop: "text",
                    uselang: variant,
                    disablelimitreport: true,
                    pst: true,
                })).parse.text["*"]));
                let converted = parsed.find("#converted").text();
                if (this.config.useOpenCC) {
                    const occMappings = [];
                    converted = converted.replace(REGEXP.noOCC, (_, content) => `<!--noOCC-->${occMappings.push(content) - 1}<!--/noOCC-->`);
                    const occVariant = variant.replace("hans", "cn").replace(/zh-(?:han)?/, "").replace("tw", "twp");
                    const converter = OpenCC.Converter({ from: occVariant, to: occVariant });
                    converted = converter(converted);
                    converted = converted.replace(REGEXP.noOCC, (_, index) => `<!--noOCC-->${occMappings[index]}<!--/noOCC-->`);
                }
                const final = this.config.manualAction[variant]?.(converted) || converted;
                const restored = restoreWikitext(final, mappings);
                this.addVariant(variant, restored);
            }
        }
        async saveChanges() {
            console.log("[VariantConverter] Saved changes", await Promise.allSettled(this.config.main.map((variant) => {
                const text = this.textInputs[variant].getValue();
                return api.postWithToken("csrf", {
                    action: "edit",
                    assertuser: username,
                    title: variantPage(variant),
                    text,
                    summary: `自动转换自[[${pagename}]]`,
                    tags: "VariantConverter|Automation tool",
                    watchlist: this.config.watchlist,
                });
            }).concat(Object.entries(this.config.dependent).map(([variant, parent]) => {
                const text = this.textInputs[parent].getValue();
                return api.postWithToken("csrf", {
                    action: "edit",
                    assertuser: username,
                    title: variantPage(variant),
                    text,
                    summary: `自动转换自[[${pagename}]](同步${parent})`,
                    tags: "VariantConverter|Automation tool",
                    watchlist: this.config.watchlist,
                });
            }))));
        }
    }
    _a = AIVCWindow;
    AIVCWindow.static = {
        ...Reflect.get(_b, "static", _a),
        tagName: "div",
        name: "lr-aivc",
        title: wgULS("自动繁简转换工具", "自動繁簡轉換工具"),
        actions: [
            {
                action: "cancel",
                label: "取消",
                flags: ["safe", "close", "destructive"],
                modes: "config",
            },
            {
                action: "continue",
                label: wgULS("继续", "繼續"),
                flags: ["primary", "progressive"],
                modes: "config",
            },
            {
                action: "back",
                label: "返回",
                flags: ["safe", "back"],
                modes: "confirm",
            },
            {
                action: "submit",
                label: wgULS("确认", "確認"),
                flags: ["primary", "progressive"],
                modes: "confirm",
            },
        ],
    };
    const $body = $(document.body);
    const windowManager = new OO.ui.WindowManager();
    $body.append(windowManager.$element);
    const aivcDialog = new AIVCWindow({
        size: "large",
        data: {
            config: lrAivc,
            prepopContent,
        },
    });
    windowManager.addWindows([aivcDialog]);
    $(mw.util.addPortletLink("p-cactions", "#", wgULS("自动繁简转换", "自動繁簡轉換"), "ca-VariantConverter", wgULS("自动同步界面消息的繁简版本", "自動同步介面消息的繁簡版本"))).on("click", (e) => {
        e.preventDefault();
        $("#mw-notification-area").appendTo($body);
        windowManager.openWindow(aivcDialog);
    });
})());  


/* </pre> */
/* </pre> */

2025年7月26日 (六) 00:10的版本

/**
 * -------------------------------------------------------------------------
 * !!! DON'T MODIFY THIS PAGE MANUALLY, YOUR CHANGES WILL BE OVERWRITTEN !!!
 * -------------------------------------------------------------------------
 */
var _addText = '{{GHIACode|page=GHIA:MoegirlPediaInterfaceCodes/blob/master/src/gadgets/interfaceVariantConverter/Gadget-interfaceVariantConverter.js|user=[[U:星海子]]|co-authors=|longId=a157f65a20db84d70f63275717dff38cbffb9db9|shortId=a157f65a|summary=chore}}'; 

/* <pre> */

"use strict";$(()=>(async()=>{var t,e;const i=mw.config.get("wgPageName"),n=mw.config.get("wgUserName"),s=mw.config.get("wgArticleId"),o=i.replace(/\/.*?$/,""),a=new mw.Api,r=/m?zh\.moegirl\.org\.cn/.test(location.hostname)?a:new mw.ForeignApi("https://mzh.moegirl.org.cn/api.php",{anonymous:!0}),c=$.extend({main:["zh-cn","zh-tw","zh-hk"],dependent:{"(main)":"zh-cn","zh-hans":"zh-cn","zh-hant":"zh-tw"},noteTA:{G1:"MediaWiki"},autoPopulate:!0,useOpenCC:!0,manualAction:{"zh-hk":t=>t.replaceAll("户","戶"),"zh-tw":t=>t.replaceAll("名稱空間","命名空間").replaceAll("記憶體","內存")},watchlist:"nochange"},window.lr_aivc);let h="";try{h=c.autoPopulate?(await a.get({action:"parse",assertuser:n,pageid:s,prop:"wikitext"})).parse.wikitext["*"]:""}catch{}const variantPage=t=>"(main)"===t?`${o}`:`${o}/${t}`,w=/-{([\s\S]*?)}-/g,l=/-\\{([\s\S]*?)}\\-/g,O=/<nowiki>([\s\S]*?)<\/nowiki>/g,g=/\[\[([\s\S]*?)(?:#([\s\S]*?))?(\|[\s\S]*?)?\]\]/g,p=/([^[])\[([^[]+?)( [\s\S]+?)?\]([^\]])/g,d=/\{\{([\s\S]*?)\}\}/g,m=/&([a-zA-Z0-9#]+);/g,u=/<!--noOCC-->([\s\S]*?)<!--\/noOCC-->/gi,restoreWikitext=(t,e)=>{const i=[];let n=t;return n=n.replace(O,(t,e)=>`<nowiki>${i.push(e)-1}</nowiki>`),n=n.replace(m,(t,i)=>`&${e[i]};`),n=n.replace(d,(t,i)=>{const n=i.split("|"),s=e[n[0]];return n.shift(),`${n.reduce((t,i)=>{const[n,...s]=i.split("=");return s.length?`${t}|${e[n]}=${s.join("=")}`:`${t}|${i}`},`{{${s}`)}}}`}),n=n.replace(p,(t,i,n,s,o)=>`${i}[${e[n]}${s||""}]${o}`),n=n.replace(g,(t,i,n,s)=>n||s?`[[${s?e[i]:i}${e[n]?`#${e[n]}`:""}${s||""}]]`:t),n=n.replace(O,(t,e)=>`<nowiki>${i[e]}</nowiki>`),n=n.replace(l,(t,i)=>`-{${e[i]??i}}-`),n};class AIVCWindow extends(e=OO.ui.ProcessDialog){constructor(t){super(t),this.config=t.data.config,this.prepopContent=t.data.prepopContent}initialize(){super.initialize(),this.configPanel=new OO.ui.PanelLayout({scrollable:!1,expanded:!1,padded:!0}),this.confirmPanel=new OO.ui.PanelLayout({scrollable:!1,expanded:!1,padded:!0}),this.ogText=new OO.ui.MultilineTextInputWidget({value:this.prepopContent,autosize:!0});const t=new OO.ui.FieldLayout(this.ogText,{label:wgULS("原始内容","原始內容"),align:"top"});this.mainVariants=new OO.ui.TextInputWidget({value:this.config.main.join(";")});const e=new OO.ui.FieldLayout(this.mainVariants,{label:wgULS("主要变体","主要變体"),align:"top"});this.depVariants=new OO.ui.TextInputWidget({value:Object.entries(this.config.dependent).map(([t,e])=>`${t}:${e}`).join(";")});const i=new OO.ui.FieldLayout(this.depVariants,{label:wgULS("依赖变体","依賴變体"),align:"top"});var n;this.noteTAParams=new OO.ui.TextInputWidget({value:(n=this.config.noteTA,Object.entries(n).map(([t,e])=>`${t}=${e}`).join("|"))});const s=new OO.ui.FieldLayout(this.noteTAParams,{label:wgULS("NoteTA参数","NoteTA參數"),align:"top"});this.occCheckbox=new OO.ui.CheckboxInputWidget({selected:this.config.useOpenCC});const o=new OO.ui.FieldLayout(this.occCheckbox,{label:"使用OpenCC",align:"inline"});this.configPanel.$element.append(t.$element,e.$element,i.$element,s.$element,o.$element),this.stackLayout=new OO.ui.StackLayout({items:[this.configPanel,this.confirmPanel]}),this.ogText.connect(this,{resize:"updateSize"}),this.$body.append(this.stackLayout.$element)}getBodyHeight(){return this.stackLayout.getCurrentItem().$element.outerHeight(!0)}getSetupProcess(t){return super.getSetupProcess(t).next(()=>{this.actions.setMode("config"),this.stackLayout.setItem(this.configPanel)},this)}getReadyProcess(t){return super.getReadyProcess(t).next(()=>{this.ogText.focus()},this)}getActionProcess(t){if("cancel"===t)return new OO.ui.Process(()=>{this.close({action:t})},this);if("continue"===t)return new OO.ui.Process($.when((async()=>{if(this.config=$.extend(this.config,{main:this.mainVariants.getValue().split(";"),dependent:Object.fromEntries(this.depVariants.getValue().split(";").map(t=>t.split(":"))),noteTAStr:this.noteTAParams.getValue(),useOpenCC:this.occCheckbox.isSelected(),dependentInv:{}}),this.config.main.includes("(main)"))throw new OO.ui.Error(wgULS("主页面不得作为主要变体","主頁面不得作為主要變体"));this.config.main.forEach(t=>this.config.dependentInv[t]=[t]);try{Object.entries(this.config.dependent).forEach(([t,e])=>this.config.dependentInv[e].push(t))}catch{throw console.error("[VariantConverter] Error: Key not found in dependentInv. Config dump:",this.config),new OO.ui.Error(wgULS("依赖变体格式错误,请检查控制台","依賴變体格式錯誤,請檢查控制臺"))}this.textInputs={},this.confirmPanel.$element.empty();try{await this.getVariants(this.ogText.getValue()),this.actions.setMode("confirm"),this.stackLayout.setItem(this.confirmPanel),this.updateSize()}catch(t){throw console.error("[VariantConverter] Error:",t),new OO.ui.Error(t)}})()).promise(),this);if("back"===t)this.actions.setMode("config"),this.stackLayout.setItem(this.configPanel),this.updateSize();else if("submit"===t)return new OO.ui.Process($.when((async()=>{try{await this.saveChanges(),this.close({action:t}),mw.notify("保存成功!",{title:wgULS("自动繁简转换工具","自動繁簡轉換工具"),type:"success",tag:"lr-aivc"}),setTimeout(()=>location.reload(),730)}catch(t){throw console.error("[VariantConverter] Error:",t),new OO.ui.Error(t)}})()).promise(),this);return super.getActionProcess(t)}addVariant(t,e){this.textInputs[t]=new OO.ui.MultilineTextInputWidget({value:e,autosize:!0});const i=new OO.ui.FieldLayout(this.textInputs[t],{label:t,align:"top"});this.textInputs[t].connect(this,{resize:"updateSize"}),this.confirmPanel.$element.append(i.$element),window?.InPageEdit?.quickDiff&&this.confirmPanel.$element.append(new OO.ui.FieldLayout(new OO.ui.Widget({content:[new OO.ui.HorizontalLayout({items:this.config.dependentInv[t].map(e=>new OO.ui.ButtonWidget({label:`${wgULS("对比","對比")}${"(main)"===e?wgULS("主页面","主頁面"):e}`}).on("click",()=>window.InPageEdit.quickDiff({fromtitle:variantPage(e),totext:this.textInputs[t].getValue(),pageName:variantPage(e),isPreview:!0})))})]})).$element)}async getVariants(t){this.confirmPanel.$element.append(`<p>${wgULS("请确认以下转换是否正确","請確認以下轉換是否正確")}:</p>`),!window.OpenCC&&this.config.useOpenCC&&await libCachedCode.injectCachedCode("https://npm.elemecdn.com/opencc-js@latest","script");const{replaced:e,mappings:i}=(t=>{const e=[],i=[];let n=t;return n=n.replace(w,(t,e)=>`-\\{${e}}\\-`),n=n.replace(O,(t,i)=>`<nowiki>${e.push(i)-1}</nowiki>`),n=n.replace(g,(t,e,n,s)=>n||s?`[[${s?i.push(e)-1:e}${n?"#"+(i.push(n)-1):""}${s||""}]]`:t),n=n.replace(p,(t,e,n,s,o)=>`${e}[${i.push(n)-1}${s||""}]${o}`),n=n.replace(d,(t,e)=>{const n=e.split("|");return i.push(n[0]),n.shift(),`${n.reduce((t,e)=>{const[n,...s]=e.split("=");return s.length?`${t}|${i.push(n)-1}=${s.join("=")}`:`${t}|${e}`},"{{"+(i.length-1))}}}`}),n=n.replace(l,(t,e)=>`-\\{${i.push(e||"")-1}}\\-`),n=n.replace(m,(t,e)=>`&${i.push(e)-1};`),n=n.replace(O,(t,i)=>`<nowiki><nowiki>${e[i]}</nowiki></nowiki>`),{replaced:n,mappings:i}})(t);for(const t of this.config.main){if("(main)"===t)continue;const s=`{{NoteTA|${this.config.noteTAStr}}}<pre id="converted">-{}-${e}</pre>`;let o=$($.parseHTML((await r.post({action:"parse",assertuser:n,text:s,contentmodel:"wikitext",prop:"text",uselang:t,disablelimitreport:!0,pst:!0})).parse.text["*"])).find("#converted").text();if(this.config.useOpenCC){const e=[];o=o.replace(u,(t,i)=>`\x3c!--noOCC--\x3e${e.push(i)-1}\x3c!--/noOCC--\x3e`);const i=t.replace("hans","cn").replace(/zh-(?:han)?/,"").replace("tw","twp");o=OpenCC.Converter({from:i,to:i})(o),o=o.replace(u,(t,i)=>`\x3c!--noOCC--\x3e${e[i]}\x3c!--/noOCC--\x3e`)}const a=this.config.manualAction[t]?.(o)||o,c=restoreWikitext(a,i);this.addVariant(t,c)}}async saveChanges(){console.log("[VariantConverter] Saved changes",await Promise.allSettled(this.config.main.map(t=>{const e=this.textInputs[t].getValue();return a.postWithToken("csrf",{action:"edit",assertuser:n,title:variantPage(t),text:e,summary:`自动转换自[[${i}]]`,tags:"VariantConverter|Automation tool",watchlist:this.config.watchlist})}).concat(Object.entries(this.config.dependent).map(([t,e])=>{const s=this.textInputs[e].getValue();return a.postWithToken("csrf",{action:"edit",assertuser:n,title:variantPage(t),text:s,summary:`自动转换自[[${i}]](同步${e})`,tags:"VariantConverter|Automation tool",watchlist:this.config.watchlist})}))))}}t=AIVCWindow,AIVCWindow.static={...Reflect.get(e,"static",t),tagName:"div",name:"lr-aivc",title:wgULS("自动繁简转换工具","自動繁簡轉換工具"),actions:[{action:"cancel",label:"取消",flags:["safe","close","destructive"],modes:"config"},{action:"continue",label:wgULS("继续","繼續"),flags:["primary","progressive"],modes:"config"},{action:"back",label:"返回",flags:["safe","back"],modes:"confirm"},{action:"submit",label:wgULS("确认","確認"),flags:["primary","progressive"],modes:"confirm"}]};const C=$(document.body),f=new OO.ui.WindowManager;C.append(f.$element);const S=new AIVCWindow({size:"large",data:{config:c,prepopContent:h}});f.addWindows([S]),$(mw.util.addPortletLink("p-cactions","#",wgULS("自动繁简转换","自動繁簡轉換"),"ca-VariantConverter",wgULS("自动同步界面消息的繁简版本","自動同步介面消息的繁簡版本"))).on("click",t=>{t.preventDefault(),$("#mw-notification-area").appendTo(C),f.openWindow(S)})})()); 

/* </pre> */