User:CFA/scripts/attributetranslation.js
Appearance
< User:CFA
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | This user script seems to have a documentation page at User:CFA/scripts/attributetranslation. |
(function () {
'use strict';
const ts = Date.now() + (29 * 24 * 60 * 60 * 1000);
const pageTitle = mw.config.get('wgPageName').replace(/_/g, ' ');
function createInputGUI(contributors) {
var gui = document.createElement('div');
gui.style.position = 'fixed';
gui.style.top = '50%';
gui.style.left = '50%';
gui.style.transform = 'translate(-50%, -50%)';
gui.style.backgroundColor = '#f8f9fa';
gui.style.border = '1px solid #a2a9b1';
gui.style.padding = '20px';
gui.style.zIndex = 10000;
gui.style.overflowY = 'auto';
gui.style.maxHeight = '80vh';
gui.innerHTML = `
<label for="langCode" style="font-weight:bold">Language code</label>
<p style="font-size: 50%;">The two-letter language code of the Wikipedia that this article was translated from.</p>
<input type="text" id="langCode" placeholder="e.g. zh, es, fr"><br><br>
<label for="articleName" style="font-weight:bold">Article name</label>
<p style="font-size: 50%;">The name of the page on the other Wikipedia that this article was translated from.</p>
<input type="text" id="articleName" placeholder="e.g. 维基百科"><br><br>
<label for="addTranslatedPageTemplate" style="font-weight:bold">
<input checked type="checkbox" id="addTranslatedPageTemplate"> Add {{Translated page}} to talk page
</label>
<p style="font-size: 50%;margin-bottom:1rem;">Add <a href="/wiki/Template:Translated page">{{Translated page}}</a> to the talk page <a href="/wiki/Help:Translation#License requirements">if</a> the translated content is significant.</p>
<label style="font-weight:bold">Warn users</label>
<p style="font-size: 50%;">Send a notice to the user(s) who added the non-attributed text.</p>
<div id="contributorsContainer">
<div id="contributorsList"></div>
</div><br>
<button id="submitTranslation">Submit</button>
<button id="closeGUI">Close</button>
<div id="logContainer" style="display: none; margin-top: 20px; border-top: 1px solid #a2a9b1; padding-top: 10px;">
<h3>Log</h3>
<ul id="logList" style="list-style-type: none; padding-left: 0;"></ul>
</div>
`;
document.body.appendChild(gui);
var contributorsList = document.getElementById('contributorsList');
if (!contributorsList) {
console.error('Contributors list container not found.');
return;
}
contributors.forEach(function (contributor) {
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.style = "transform: scale(0.75);margin-right:3px;";
checkbox.name = 'contributors';
checkbox.value = contributor.username;
var label = document.createElement('label');
label.style = "font-size:75%";
label.appendChild(checkbox);
label.appendChild(document.createTextNode(`${contributor.username} — ${contributor.edits} edit${contributor.edits === 1 ? '' : 's'}${contributor.isCreator ? ' (Page Creator)' : ''}`));
label.appendChild(document.createElement('br'));
contributorsList.appendChild(label);
});
document.getElementById('submitTranslation').addEventListener('click', function () {
var langCode = document.getElementById('langCode').value.trim();
var articleName = document.getElementById('articleName').value.trim();
var selectedContributors = Array.from(document.querySelectorAll('input[name=contributors]:checked')).map(function (checkbox) {
return checkbox.value;
});
var addTemplate = document.getElementById('addTranslatedPageTemplate').checked;
if (langCode && articleName) {
processTranslation(langCode, articleName, selectedContributors, addTemplate);
document.getElementById('logContainer').style.display = 'block';
} else {
alert('Please fill in both fields.');
}
});
document.getElementById('closeGUI').addEventListener('click', function () {
document.body.removeChild(gui);
});
}
function processTranslation(langCode, articleName, selectedContributors, addTemplate) {
var editSummary = `This article contains content translated from the Wikipedia article at [[${langCode}:${articleName}]]; see its history for attribution. ([[User:CFA/scripts/AttributeTranslation|AT]])`;
var tasksCompleted = 0;
var totalTasks = 1 + (addTemplate ? 1 : 0) + selectedContributors.length;
var logList = document.getElementById('logList');
function addLogEntry(message, success) {
var listItem = document.createElement('li');
listItem.style.display = 'flex';
listItem.style.alignItems = 'center';
var checkmark = document.createElement('span');
checkmark.style.display = 'inline-block';
checkmark.style.width = '16px';
checkmark.style.height = '16px';
checkmark.style.marginRight = '8px';
checkmark.style.backgroundColor = success ? 'green' : 'red';
checkmark.style.borderRadius = '50%';
listItem.appendChild(checkmark);
listItem.appendChild(document.createTextNode(message));
logList.appendChild(listItem);
}
function checkCompletion() {
tasksCompleted++;
if (tasksCompleted === totalTasks) {
setTimeout(() => {
location.reload();
}, 1000);
}
}
$.ajax({
url: mw.util.wikiScript('api'),
type: 'GET',
data: {
format: 'json',
action: 'query',
prop: 'revisions',
rvprop: 'content',
titles: pageTitle
},
success: function (data) {
var pages = data.query.pages;
var pageContent = '';
for (var pageId in pages) {
if (pages.hasOwnProperty(pageId)) {
pageContent = pages[pageId].revisions[0]['*'];
}
}
pageContent += '\n';
$.ajax({
url: mw.util.wikiScript('api'),
type: 'POST',
data: {
format: 'json',
action: 'edit',
title: pageTitle,
text: pageContent,
summary: editSummary,
minor: true,
watchlist: 'nochange',
token: mw.user.tokens.get('csrfToken')
},
success: function () {
console.log('Dummy edit successful');
addLogEntry('Added dummy edit to article', true);
checkCompletion();
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('Error performing dummy edit:', textStatus, errorThrown);
addLogEntry('Failed to add dummy edit to article', false);
checkCompletion();
}
});
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('Error retrieving page content:', textStatus, errorThrown);
addLogEntry('Failed to retrieve page content', false);
checkCompletion();
}
});
if (addTemplate) {
var talkPageTitle = 'Talk:' + pageTitle;
$.ajax({
url: mw.util.wikiScript('api'),
type: 'GET',
data: {
format: 'json',
action: 'query',
prop: 'revisions',
rvprop: 'content',
titles: talkPageTitle
},
success: function (data) {
var pages = data.query.pages;
var talkPageContent = '';
var talkPageExists = false;
for (var pageId in pages) {
if (pages.hasOwnProperty(pageId)) {
if (pages[pageId].revisions) {
talkPageExists = true;
talkPageContent = pages[pageId].revisions[0]['*'];
}
}
}
if (talkPageExists) {
var existingTemplateMatch = talkPageContent.match(/{{\s*(?:translationsource|translated article|translated|tradotto da|traducido ref|translated page|překlad|translated from)\s*(\|.*)?}}/i);
if (existingTemplateMatch) {
console.log('Template already present');
addLogEntry('{{Translated page}} already exists on talk page', true);
checkCompletion();
return;
}
if (talkPageContent.includes('{{WikiProject banner shell')) {
var bannerShellEndIndex = talkPageContent.lastIndexOf('}}');
if (bannerShellEndIndex !== -1) {
talkPageContent = talkPageContent.slice(0, bannerShellEndIndex + 2) + '\n{{translated page|' + langCode + '|' + articleName + '|small=no}}' + talkPageContent.slice(bannerShellEndIndex + 2);
console.log('Added {{translated page}} to talk page');
}
} else {
talkPageContent += '\n{{translated page|' + langCode + '|' + articleName + '|small=no}}';
console.log('Added {{translated page}} to talk page');
}
$.ajax({
url: mw.util.wikiScript('api'),
type: 'POST',
data: {
format: 'json',
action: 'edit',
title: talkPageTitle,
summary: 'Adding {{translated page}} attribution ([[User:CFA/scripts/AttributeTranslation|AT]])',
text: talkPageContent,
token: mw.user.tokens.get('csrfToken')
},
success: function () {
console.log('Talk page updated');
addLogEntry('Added {{translated page}} to talk page', true);
checkCompletion();
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('Error updating talk page:', textStatus, errorThrown);
addLogEntry('Failed to add template to talk page', false);
checkCompletion();
}
});
} else {
$.ajax({
url: mw.util.wikiScript('api'),
type: 'POST',
data: {
format: 'json',
action: 'edit',
title: talkPageTitle,
summary: 'Adding {{Translated page}} attribution ([[User:CFA/scripts/AttributeTranslation|AT]])',
text: '{{translated page|' + langCode + '|' + articleName + '|small=no}}',
token: mw.user.tokens.get('csrfToken')
},
success: function () {
console.log('Talk page created and template added');
addLogEntry('Added {{translated page}} to talk page', true);
checkCompletion();
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('Error creating talk page:', textStatus, errorThrown);
addLogEntry('Failed to create talk page', false);
checkCompletion();
}
});
}
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('Error retrieving talk page:', textStatus, errorThrown);
addLogEntry('Failed to retrieve talk page', false);
checkCompletion();
}
});
}
selectedContributors.forEach(function (contributor) {
notifyContributor(contributor, langCode, articleName);
});
function notifyContributor(contributor, langCode, articleName) {
var subst = "subst:";
var sig = "~~" + "~~";
var notificationMessage = `{{${subst}uw-translation|1=${langCode}:${articleName}|to=${pageTitle}}} ${sig}`;
$.ajax({
url: mw.util.wikiScript('api'),
type: 'POST',
data: {
format: 'json',
action: 'edit',
title: 'User talk:' + contributor,
summary: 'Adding non-attributed translation notice ([[User:CFA/scripts/AttributeTranslation|AT]])',
section: 'new',
watchlist: 'nochange',
sectiontitle: 'Non-attributed translations',
text: notificationMessage,
token: mw.user.tokens.get('csrfToken')
},
success: function () {
console.log('Notification sent to user talk page');
addLogEntry(`Warned user (${contributor})`, true);
checkCompletion();
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('Error sending notification:', textStatus, errorThrown);
addLogEntry(`Failed to warn user (${contributor})`, false);
if (confirm("Could not notify contributor. Retry?")) {
notifyContributor(contributor, langCode, articleName);
} else {
checkCompletion();
}
}
});
}
}
function getPageContributors(pageTitle, callback) {
$.ajax({
url: mw.util.wikiScript('api'),
type: 'GET',
data: {
format: 'json',
action: 'query',
prop: 'revisions',
rvprop: 'user',
titles: pageTitle,
rvlimit: 'max',
rvdir: 'newer'
},
success: function (data) {
var pages = data.query.pages;
var contributors = [];
for (var pageId in pages) {
if (pages.hasOwnProperty(pageId)) {
var revisions = pages[pageId].revisions;
var creator = true;
revisions.forEach(function (revision) {
if (revision.user && revision.user !== '') {
var contributorIndex = contributors.findIndex(function (item) {
return item.username === revision.user;
});
if (contributorIndex === -1) {
contributors.push({ username: revision.user, edits: 1, isCreator: creator });
} else {
contributors[contributorIndex].edits++;
}
creator = false;
}
});
}
}
callback(contributors);
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('Error retrieving page contributors:', textStatus, errorThrown);
}
});
}
function addButtonToToolbar() {
var allowedNamespaces = [0, 118];
var currentNamespace = mw.config.get('wgNamespaceNumber');
if (allowedNamespaces.includes(currentNamespace)) {
mw.util.addPortletLink(
'p-cactions',
'#',
'Translation attribution',
'ca-translation-attribution',
'AttributeTranslation',
null,
null
);
document.getElementById('ca-translation-attribution').addEventListener('click', function () {
getPageContributors(pageTitle, function (contributors) {
createInputGUI(contributors);
});
});
}
}
addButtonToToolbar();
})();