User:CFA/scripts/attributetranslation.js
//<nowiki>
(function () {
'use strict';
const ts = Date.now() + (29 * 24 * 60 * 60 * 1000);
const pageName = mw.config.get('wgPageName');
const pageTitle = pageName.replace(/_/g, ' ');
function getTalkPageTitleFrom(titleOrName) {
const t = mw.Title.newFromText(titleOrName);
if (!t) return 'Talk:' + pageTitle;
const talk = t.getTalkPage();
return talk ? talk.getPrefixedText() : 'Talk:' + pageTitle;
}
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>
<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',
rvslots: 'main',
titles: pageTitle
},
success: function (data) {
var pages = data.query.pages;
var pageContent = '';
for (var pageId in pages) {
if (!pages.hasOwnProperty(pageId)) continue;
var rev = pages[pageId].revisions && pages[pageId].revisions[0];
pageContent = (rev && rev.slots && (rev.slots.main['*'] || rev.slots.main['content'])) || '';
}
pageContent += '\n\u200B';
$.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 = getTalkPageTitleFrom(pageName);
$.ajax({
url: mw.util.wikiScript('api'),
type: 'GET',
data: {
format: 'json',
action: 'query',
prop: 'revisions',
rvprop: 'content',
rvslots: 'main',
titles: talkPageTitle
},
success: function (data) {
var pages = data.query.pages;
var talkPageContent = '';
var talkPageExists = false;
for (var pageId in pages) {
if (!pages.hasOwnProperty(pageId)) continue;
if (pages[pageId].missing === '') {
talkPageExists = false;
} else if (pages[pageId].revisions) {
talkPageExists = true;
var rev = pages[pageId].revisions[0];
talkPageContent = (rev && rev.slots && (rev.slots.main['*'] || rev.slots.main['content'])) || '';
}
}
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}} inside banner shell');
} else {
talkPageContent += '\n{{translated page|' + langCode + '|' + articleName + '|small=no}}';
}
} 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 unattributed translation notice ([[User:CFA/scripts/AttributeTranslation|AT]])',
section: 'new',
watchlist: 'nochange',
sectiontitle: 'Unattributed 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(title, callback) {
$.ajax({
url: mw.util.wikiScript('api'),
type: 'GET',
data: {
format: 'json',
action: 'query',
prop: 'revisions',
rvprop: 'user',
titles: title,
rvlimit: 'max',
rvdir: 'newer'
},
success: function (data) {
var pages = data.query.pages;
var contributors = [];
for (var pageId in pages) {
if (!pages.hasOwnProperty(pageId)) continue;
var revisions = pages[pageId].revisions || [];
var creator = true;
revisions.forEach(function (revision) {
if (revision.user && revision.user !== '') {
var idx = contributors.findIndex(function (item) {
return item.username === revision.user;
});
if (idx === -1) {
contributors.push({ username: revision.user, edits: 1, isCreator: creator });
} else {
contributors[idx].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 (e) {
e.preventDefault();
getPageContributors(pageTitle, function (contributors) {
createInputGUI(contributors);
});
});
}
}
addButtonToToolbar();
})();
//</nowiki>
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.