User:Artoria2e5/link-ts.js
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google Chrome、Firefox、Microsoft Edge及Safari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
;/**
* @file Link Translator for Chinese Wikipedia
* @author [[User:Liangent]] // initial version ([[User:Liangent/Gadgets/Toolkit/linktranslator.uncompressed.js]])
* @author [[User:Kovl]] // v2015-2-6-7-52
* @author [[User:Panintelize]] // 2016-02-06
* @author [[User:Artoria2e5]] // review, async, review-functional, KeepOriginalTextAuto
*
* To use this script, add the following line to [[User:YourName/common.js]]:
* importScript('User:Artoria2e5/link-ts.js')
*/
mw.loader.using(['jquery.ui']).then(function () {
$(function() {
function __lt_strarr_dedup(arr) {
var ret = Object.create(null);
$(arr).each(function (idx, elem) {
ret[elem] = '';
});
return Object.keys(ret);
}
/**
* @namespace UI-related text
*/
var LTUI = {
Translate: "翻译",
TranslateLinks: "翻译链接",
LinkTranslator: "链接翻译器",
TLTitle: "自动翻译从其他语言维基百科复制的文本",
SourceLang: "目标维基的语言代码:",
OriginalLink: "原链接:",
NOLINKINPAGE: "此页没有链接",
Done: "完成",
NoWikiEd: "linktranslator.js与WikiEd不兼容,请于页面右上角暂时禁用WikiEd。",
EditMessage: "由[[User:Artoria2e5/link-ts.js|链接翻译器]]自动翻译;",
// OPTION
KeepOriginalTextTsl: "以原文顯示綠鏈",
KeepOriginalTextBlue: "以原文顯示藍鍊",
KeepOriginalTextAuto: "保留[[link]]中的自动文字",
CommentOriginalLink: "注释原链接",
UseLangLink: "跨语言链接",
// STATUS
PARSEFAILED: "解析失败",
ERROR: "错误",
NOLINK: "没有链接",
MULTIPLELINK: "多个连接",
PAGESAME: "页面相同",
PAGEDIFF: "页面不同",
DONTEXIST: "页面不存在"
};
/**
* @namespace config (defaults)
*/
var LTConf = {
// TYPE: STRING
SourceLang: "en",
// TYPE: "checked=" attribute boolean
// "checked" is true;
// "" is false.
KeepOriginalTextTsl: "checked",
KeepOriginalTextBlue: "checked",
KeepOriginalTextAuto: "",
CommentOriginalLink: "",
UseLangLink: "checked"
};
// clear previous button
$('#wpLinktranslator').remove();
// secure server?
if ((mw.config.get('wgAction') == 'edit' || mw.config.get('wgAction') == 'submit') && mw.config.get('wgServer') == '//zh.wikipedia.org') {
$('#wpDiff').after('\n<input id="wpLinktranslator" value="' + LTUI.TranslateLinks + '" title="' + LTUI.TLTitle + '" type="button"/>');
$('#wpLinktranslator').click(LTClick);
}
// variables
var jobid = 0;
var ldsb = '__LEFT_DOUBLE_SQUARE_BRACKETS__';
var EXEConf;
function LTPascalCase(wordsStr){
return wordsStr.match(/([A-Z]+(?=$|[A-Z][a-z])|[A-Z]?[a-z]+)/g);
}
// on click "Translate links" #wpLinktranslator
function LTClick(event) {
event.preventDefault();
$('#linktranslator').remove();
if ($("#wikEdFrameWrapper").css("visibility") == "visible") {
alert(LTUI.NoWikiEd);
return;
}
$('<div id="linktranslator" class="plainlist" title="' + LTUI.LinkTranslator + '"><ul>' +
'<li><label for="linktranslator-source-lang">' + LTUI.SourceLang + '</label> ' +
'<input id="linktranslator-source-lang" value="' + LTConf.SourceLang + '" type="text" /></li>' +
$.map(Object.keys(LTConf).slice(1), function(v, idx){
var id = 'linktranslator-' + LTPascalCase(v).join('-');
return '<li>' +
'<label for="' + id + '">' + LTUI[v] + '</label> ' +
'<input type="checkbox" id="' + id + '"' + LTConf[v] + '></label></li>';
}).join('') + '</ul>' +
'<input id="linktranslator-translate" value="' + LTUI.Translate + '" type="button" />' + '</div>'
).dialog({
modal: false,
close: function () {
jobid++;
},
width: 500
});
$('#linktranslator-translate').click(TClick);
}
// on click "Translate" #linktranslator-translate
function TClick(event) {
event.preventDefault();
var thisjobid = jobid; // or in #wpLinktranslator's click event?
EXEConf = Object.keys(LTConf).slice(1).reduce(function(acc, v){
acc[v] = $('#linktranslator-' + LTPascalCase(v).join('-')).prop('checked');
return acc;
}, {});
EXEConf.SourceLang = $('#linktranslator-source-lang').val();
// if you don't use HTTPS, just die.
var api = 'https://' + EXEConf.SourceLang + '.wikipedia.org/w/api.php';
var wikitext = $('#wpTextbox1').val();
var links = __lt_strarr_dedup($('#wpTextbox1').val().match(/(\[\[)(?!\:?.?.?\:)(?!(Image|File))(.+?)(\|.+?)?(\]\])/g));
if (links === null) {
$('#linktranslator').text(LTUI.NOLINKINPAGE);
return;
} else {
// assert links.length != 0 here, or we have a problem with the browsr.
$('#linktranslator').dialog("option", "position", {
my: "top",
at: "top"
});
$('#linktranslator').html('<div id="linktranslator-progressbar"></div>');
$('#linktranslator-progressbar').progressbar();
}
var respcount = 0;
$(links).each(function eachlink(linkidx, linkelem) {
var link = linkelem.slice(2, -2);
var linktarget = link;
// TODO: pipe tricks like [[/subpage/]]?
var linkdisplay = EXEConf.KeepOriginalTextAuto ? link : '';
var idx = link.indexOf('|');
if (idx != -1) {
linktarget = link.substring(0, idx);
linkdisplay = link.substring(idx + 1);
}
$('#linktranslator').append('<div id="linktranslator-item-' + linkidx + '"></div>');
$('#linktranslator-item-' + linkidx).text(linkelem + ' -> ')
.append('<span class="linktranslator-item-newlink">...</span>');
// TODO: cannot identify if missing or [[zh:]] (for main page, also blank text)
$.ajax({
data: {
action: 'parse',
format: 'json',
page: linktarget,
prop: 'langlinks',
redirects: 1
},
dataType: "jsonp",
type: 'POST',
url: api,
success: function (data) {
console.log(data);
if (thisjobid != jobid) {
return;
}
var iwmatches;
var newtarget;
var newlinks;
if (data.parse) {
// request successful
iwmatches = $.grep(data.parse.langlinks, function(el){ return el.lang === 'zh' });
} else if (data.error.info) {
// request completed with error
if (data.error.info == "The page you specified doesn't exist") {
$('#linktranslator-item-' + linkidx + ' .linktranslator-item-newlink').text(LTUI.DONTEXIST);
} else {
$('#linktranslator-item-' + linkidx + ' .linktranslator-item-newlink').text(LTUI.ERROR + '(' + data.error.info + ')');
}
return;
} else {
// error without info field
$('#linktranslator-item-' + linkidx + ' .linktranslator-item-newlink').text(LTUI.PARSEFAILED);
return;
}
if (iwmatches.length === 1) {
newtarget = iwmatches[0]["*"];
if (linktarget === newtarget) {
$('#linktranslator-item-' + linkidx + ' .linktranslator-item-newlink').text(LTUI.PAGESAME);
return;
}
if (EXEConf.KeepOriginalTextBlue) {
newlinks = ldsb + newtarget + '|' + linkdisplay + ']]';
} else {
newlinks = ldsb + newtarget + ']]';
}
} else if (iwmatches.length === 0) {
if (EXEConf.UseLangLink) {
if (EXEConf.KeepOriginalTextTsl) {
newlinks = '{{tsl|' + EXEConf.SourceLang + '|' + linktarget + '||' + (linkdisplay == linktarget ? '' : linkdisplay) + '}}';
} else {
newlinks = '{{tsl|' + EXEConf.SourceLang + '|' + linktarget + '}}';
}
} else {
$('#linktranslator-item-' + linkidx + ' .linktranslator-item-newlink').text(LTUI.NOLINK);
return;
}
} else {
$('#linktranslator-item-' + linkidx + ' .linktranslator-item-newlink').text(LTUI.MULTIPLELINK);
return;
}
// EXEConf.CommentOriginalLink
var newcomment = EXEConf.CommentOriginalLink ? '<!-- ' + LTUI.OriginalLink + ldsb + link + ']] -->' : '';
// mark on dialogue
$('#linktranslator-item-' + linkidx + ' .linktranslator-item-newlink').text(newlinks.replace(new RegExp(ldsb, 'g'), '[['));
// replace all. since input is sparse, we don't care about...
wikitext = wikitext.split(links[linkidx]).join(newlinks + newcomment);
},
error: function (jqXHR, textStatus, errorThrown) {
if (thisjobid != jobid) {
return;
}
$('#linktranslator-item-' + linkidx + ' .linktranslator-item-newlink').text(LTUI.ERROR + '(' + textStatus + ')');
},
complete: function () {
if (thisjobid != jobid) {
return;
}
respcount++;
$('#linktranslator-progressbar').progressbar('value', respcount * 100 / links.length);
if (respcount >= links.length) {
$('#wpTextbox1').val(wikitext.replace(new RegExp(ldsb, 'g'), '[['));
$('#linktranslator').prepend('<div id="linktranlator-done"><strong>' + LTUI.Done + '</strong></div>');
}
}
}); // end of $.ajax
}); // end of $(links).each
$('#wpSummary').val(LTUI.EditMessage + $('#wpSummary').val()/* + JSON.stringify(EXEConf)*/);
}
});
});