/*
* @name Link Translator
*
* Originally designed by [[User:Liangent]]
* Changed by [[User:Kovl]] v2015-2-6-7-52
* Changed again by [[user:Panintelize]] 2016-02-06
* Source code is at [[User:Liangent/Gadgets/Toolkit/linktranslator.uncompressed.js]]
*
* VANDALIZED BY [[User:逆襲的天邪鬼]] v2016-11-31
*
* See also: [[zh:User:逆襲的天邪鬼/link-ts.js]]
*/
// <pre>
/**
* TODO:
*
* 1. 把中文的{{le}}、{{lang-xx}}、{{tsl}}变成对应的英文版本条目;
* 2. 使用{{Interlanguage link multi}}因为英文的{{link-zh}}并不起作用;
*/
mw.loader.using(['jquery.ui']).then(function () {
'use strict';
var LTUI = {
Translate: 'Translate',
TranslateLinks: 'Translate links',
LinkTranslator: 'Link Translator',
TLTitle: 'Translate links from Wikipedia in another language automatically',
SourceLanguageCode: 'Language code of the target Wikipedia: ',
OriginalLink: 'Original Link: ',
NOLINKINPAGE: 'There is no links in this page',
Done: 'Done',
NoWikiEd: 'Please disable WikEd before using linktranslator.js due to incompatibility',
EditMessage: '[[User:逆襲的天邪鬼/link-ts.js|Translate links]] from another Wikipedia',
// OPTION
SelectedTextOnly: 'Only process highlighted texts',
IfFound: 'If corresponding articles are found --',
KeepOriginalText: 'Keep original lagels ({{link-zh||原文|Label}})',
KeepOriginalText2: 'Keep original labels ([[English|原文]])',
CommentOriginalLink: 'Comment original links',
IfNotFound: 'Otherwise --',
UseLangLink: 'Convert it to {{link-xx}}',
MarkWrongPage: 'Mark pages which are not found in Wikipedia',
// STATUS
PARSEFAILED: 'Parse Failed',
ERROR: 'Error',
NOLINK: 'No Links',
MULTIPLELINK: 'Multiple Links',
PAGESAME: 'Same page',
PAGEDIFF: 'Different pages',
DONTEXIST: 'Page Not Found'
};
var LTConf = {
SourceLanguageCode: 'zh',
KeepOriginalText: 'checked', // 'checked' or ''
KeepOriginalText2: 'checked',
CommentOriginalLink: '',
UseLangLink: 'checked',
SelectedTextOnly: 'checked',
MarkWrongPage: 'checked',
};
// variables
var currentJobid = 0;
var LDSB = '__LEFT_DOUBLE_SQUARE_BRACKETS__';
var EXEConf;
/**
* 调用维基百科API来转换条目标题
*/
var callApi = function (options) {
var links = options.links || [];
var callback = options.callback || (function () {});
var failure = options.failure || (function () {});
var lang = options.lang || 'en';
var tolang = options.tolang || mw.config.get('wgContentLanguage');
var jobid = options.jobid || currentJobid;
// 标题去重,同时将这些标题分组,因为API只允许一次性最多提交50个标题
var map = {};
var i;
for (i=0; i<links.length; i++) {
map[links[i]] = true;
}
var queue = [];
var queue2 = [];
var m = 0, n = 0;
for (var j in map) {
queue.push(j);
m++;
if (m === 50) {
m = 0;
queue2.push(queue);
queue = [];
n++;
}
}
if (queue.length > 0) {
queue2.push(queue);
n++;
}
// 开始处理
var stop = false;
var langlinks = {};
var done = function (data) {
if (data.query) {
// 獲取原來的標題
var orinTitle = {};
var convert = function (arr) {
if (arr) {
for (var i=0; i<arr.length; i++) {
if (orinTitle[arr[i].from]) {
orinTitle[arr[i].to] = orinTitle[arr[i].from];
} else {
orinTitle[arr[i].to] = arr[i].from;
}
}
}
};
convert(data.query.normalized);
convert(data.query.converted);
convert(data.query.redirects);
// 標明翻譯情況
var pages = data.query.pages;
for (var pageid in pages) {
var page = pages[pageid];
var title = page.title;
if (orinTitle[title]) {
title = orinTitle[title];
}
if (page.missing !== undefined) {
// 页面不存在
langlinks[title] = undefined;
} else if (page.langlinks) {
langlinks[title] = page.langlinks[0]['*'];
} else {
// 没有对应条目
langlinks[title] = null;
}
}
}
n--;
if (n === 0 && !stop) {
callback(langlinks);
}
};
var error = function (jqXHR, textStatus, errorThrown) {
stop = true;
if (jobid === currentJobid) {
failure(langlinks);
}
};
var process = function (links) {
if (jobid !== currentJobid) {
stop = true;
return;
}
$.ajax({
data: {
action: 'query',
prop: 'langlinks',
lllang: tolang,
format: 'json',
redirects: true,
converttitles: true,
lllimit: 50,
titles: links.join('|'),
},
dataType: 'jsonp',
type: 'POST',
url: 'https://' + lang + '.wikipedia.org/w/api.php',
success: done,
error: error,
});
};
for (i=0; i<queue2.length && !stop; i++) {
process(queue2[i]);
}
};
/**
* 根据要求,将跨语言链接变成普通链接或{{link-xx}}(英文维基没有{{tsl}})。Category会被特殊处理。
*/
var makeLink = function (options) {
var link = options.link || { target: '', display: '' };
var lang = options.lang || '';
var newTarget = options.newTarget;
var output = '';
if (!link) {
return '';
}
var makeNormalLink = function (target, display) {
if (target === display || display === '') {
return LDSB + target + ']]';
} else {
return LDSB + target + '|' + display + ']]';
}
};
// 禁止把页面分类变成跨语言链接,或者在其后面附加文字(除非是[[Category:XXX|*]]那种)
if (link.target.toLowerCase().indexOf('category:') === 0) {
options.useLangLink = false;
options.keepOriginalText2 = (link.display !== '' && link.display !== link.target);
}
if (newTarget === null) {
// 没有对应英文条目
if (options.useLangLink) {
if (options.keepOriginalText) {
return '{{link-' + lang + '||' + link.target + '|' + link.display + '}}';
} else {
return '{{link-' + lang + '||' + link.target + '}}';
}
} else {
if (options.markWrongPage) {
return '<!-- ' + LTUI.NOLINK + ' -->' + makeNormalLink(link.target, link.display);
} else {
return makeNormalLink(link.target, link.display);
}
}
} else if (newTarget === undefined) {
// 页面不存在
if (options.markWrongPage) {
return '<!-- ' + LTUI.DONTEXIST + ' -->' + makeNormalLink(link.target, link.display);
} else {
return makeNormalLink(link.target, link.display);
}
} else {
if (options.keepOriginalText2) {
output = makeNormalLink(newTarget, link.display || link.target);
} else {
output = makeNormalLink(newTarget, '');
}
}
if (options.commentOriginalLink) {
output = '<!-- ' + makeNormalLink(link.target, link.display) + ' -->' + output;
}
return output;
};
/**
* 开始进行处理
*/
var processLinks = function (event) {
event.preventDefault();
var jobid = currentJobid;
EXEConf = {
KeepOriginalText: $('#linktranslator-keep-original').prop('checked'),
KeepOriginalText2: $('#linktranslator-keep-original2').prop('checked'),
CommentOriginalLink: $('#linktranslator-comment-link').prop('checked'),
UseLangLink: $('#linktranslator-lang-link').prop('checked'),
SelectedTextOnly: $('#linktranslator-selected-text').prop('checked'),
MarkWrongPage: $('#linktranslator-markwrongpage').prop('checked'),
};
LTConf.SourceLanguageCode = $('#linktranslator-source-lang').val();
var textBox = document.getElementById('wpTextbox1');
var wikitext = textBox.value;
if (EXEConf.SelectedTextOnly && textBox.selectionEnd - textBox.selectionStart > 0) {
wikitext = wikitext.substring(textBox.selectionStart, textBox.selectionEnd);
}
var links = wikitext.match(/(\[\[)(?!\:?.?.?\:)(?!Image:)(?!File:)(.+?)(\|.+?)?(\]\])/g);
if (links === null) {
$('#linktranslator').text(LTUI.NOLINKINPAGE);
return;
} else {
$('#linktranslator').dialog( 'option', 'position', { my: 'top', at: 'top'} );
$('#linktranslator').html('<div id="linktranslator-progressbar"></div>');
$('#linktranslator-progressbar').progressbar();
}
// 整合各links
var realLinks = [];
var links2 = [];
for (var i=0; i<links.length; i++) {
var link = links[i].slice(2, -2);
var linktarget = link;
var linkdisplay = link;
var idx = link.indexOf('|');
if (idx != -1) {
linktarget = link.substring(0, idx);
linkdisplay = link.substring(idx + 1);
}
$('#linktranslator').append('<div id="linktranslator-item-' + i + '"></div>');
$('#linktranslator-item-' + i).text(links[i] + ' -> ')
.append('<span class="linktranslator-item-newlink">...</span>');
realLinks.push(linktarget);
links2.push({ target: linktarget, display: linkdisplay });
}
var apiCallback = function (langlinks) {
var code = wikitext + '';
for (var i=0; i<links2.length; i++) {
var link = links2[i];
// 处理文内链接
var linkCode = makeLink({
link: link,
newTarget: langlinks[link.target],
lang: LTConf.SourceLanguageCode,
useLangLink: EXEConf.UseLangLink,
keepOriginalText: EXEConf.KeepOriginalText,
keepOriginalText2: EXEConf.KeepOriginalText2,
commentOriginalLink: EXEConf.CommentOriginalLink,
markWrongPage: EXEConf.MarkWrongPage,
});
//mark on dialogue
$('#linktranslator-item-' + i + ' .linktranslator-item-newlink').text(linkCode.replace(new RegExp(LDSB, 'g'), '[['));
if (langlinks[link.target] === null) {
// 没有对应英文条目
if (!EXEConf.UseLangLink) {
$('#linktranslator-item-' + i + ' .linktranslator-item-newlink').text(LTUI.NOLINK);
}
} else if (langlinks[link.target] === undefined) {
// 页面不存在
$('#linktranslator-item-' + i + ' .linktranslator-item-newlink').text(LTUI.DONTEXIST);
} else if (langlinks[link.target] === link) {
$('#linktranslator-item-' + i + ' .linktranslator-item-newlink').text(LTUI.PAGESAME);
}
// only replacing the first is ok, we will run this many times
code = code.replace(links[i], linkCode);
}
return code.replace(new RegExp(LDSB, 'g'), '[[');
};
// 开始处理
// 过去是一个条目调用一次API,现在是一次性处理全部,所以滚动条已经没有意义。
// var respcount = 0;
callApi({
links: realLinks,
lang: LTConf.SourceLanguageCode,
jobid: jobid,
callback: function (langlinks) {
var newtext = apiCallback(langlinks);
//$('#linktranslator-progressbar').progressbar('value', respcount * 100 / links.length);
$('#linktranslator-progressbar').progressbar('value', 100);
$('#linktranslator').prepend('<div id="linktranlator-done"><strong>' + LTUI.Done + '</strong></div>');
if (EXEConf.SelectedTextOnly && textBox.selectionEnd - textBox.selectionStart > 0) {
textBox.setRangeText(newtext);
} else {
textBox.value = newtext;
}
$('#wpSummary').val(LTUI.EditMessage + $('#wpSummary').val());
},
failure: function (langlinks) {
$('#linktranslator').prepend('<div id="linktranlator-done" style="color:red;"><strong>' + LTUI.ERROR + '</strong></div>');
},
});
};
// clear previous button
$('#wpLinktranslator').remove();
// secure server?
var wgAction = mw.config.get('wgAction');
if (wgAction == 'edit' || wgAction == 'submit') {
$('#wpDiff').after('\n<input id="wpLinktranslator" value="' + LTUI.TranslateLinks + '" title="' + LTUI.TLTitle + '" type="button"/>');
$('#wpLinktranslator').click(function (event) {
event.preventDefault();
$('#linktranslator').remove();
if ($('#wikEdFrameWrapper').css('visibility') === 'visible'){
alert(LTUI.NoWikiEd);
return;
}
var textBox = document.getElementById('wpTextbox1');
if (textBox.selectionEnd - textBox.selectionStart > 0) {
LTConf.SelectedTextOnly = 'checked';
} else {
LTConf.SelectedTextOnly = '';
}
$('<div id="linktranslator" title="' + LTUI.LinkTranslator + '">' +
'<label for="linktranslator-source-lang">' + LTUI.SourceLanguageCode + '</label> ' +
'<input id="linktranslator-source-lang" value="' + LTConf.SourceLanguageCode + '" type="text" /><br><br>' +
'<input type="checkbox" id="linktranslator-selected-text" ' + LTConf.SelectedTextOnly + '/> ' +
'<label for="linktranslator-selected-text">' + LTUI.SelectedTextOnly + '</label><br>' +
'<br>' + LTUI.IfFound + '<br><br>' +
'<input type="checkbox" id="linktranslator-comment-link" ' + LTConf.CommentOriginalLink + '/> ' +
'<label for="linktranslator-comment-link">' + LTUI.CommentOriginalLink + '</label><br>' +
'<input type="checkbox" id="linktranslator-keep-original2" ' + LTConf.KeepOriginalText2 + '/> ' +
'<label for="linktranslator-keep-original2">' + LTUI.KeepOriginalText2 + '</label><br>' +
'<br>' + LTUI.IfNotFound + '<br><br>' +
'<input type="checkbox" id="linktranslator-lang-link" ' + LTConf.UseLangLink + '/> ' +
'<label for="linktranslator-lang-link">' + LTUI.UseLangLink + '</label><br>' +
'<input type="checkbox" id="linktranslator-keep-original" ' + LTConf.KeepOriginalText + '/> ' +
'<label for="linktranslator-keep-original">' + LTUI.KeepOriginalText + '</label><br>' +
'<input type="checkbox" id="linktranslator-markwrongpage" ' + LTConf.MarkWrongPage + '/> ' +
'<label for="linktranslator-markwrongpage">' + LTUI.MarkWrongPage + '</label><br>' +
'<br><input class="mw-ui-button mw-ui-constructive" id="linktranslator-translate" value="' + LTUI.Translate + '" type="button" /></div>'
).dialog({
modal: false,
close: function() {
currentJobid++;
},
width: 500
});
$('#linktranslator-translate').click(processLinks);
});
}
});
// </pre>