ميدياويكي:Gadget-LinkTranslator.js

من كوبتيكبيديا
اذهب إلى التنقلاذهب الى البحث
لم تعد النسخة القابلة للطباعة مدعومة وقد تحتوي على أخطاء في العرض. يرجى تحديث علامات متصفحك المرجعية واستخدام وظيفة الطباعة الافتراضية في متصفحك بدلا منها.

ملاحظة: بعد النشر، أنت قد تحتاج إلى إفراغ الكاش الخاص بمتصفحك لرؤية التغييرات.

  • فايرفوكس / سافاري: أمسك Shift أثناء ضغط Reload، أو اضغط على إما Ctrl-F5 أو Ctrl-R (⌘-R على ماك)
  • جوجل كروم: اضغط Ctrl-Shift-R (⌘-Shift-R على ماك)
  • إنترنت إكسبلورر/إيدج: أمسك Ctrl أثناء ضغط Refresh، أو اضغط Ctrl-F5
  • أوبرا: اضغط Ctrl-F5.
//[[:en:User:Ebraminio/ArticleTranslator.js]]; [[ويكيبيديا:الميدان/تقنية/05/2012#مترجم]]
// <nowiki>
/*jslint regexp: true */
/*browser: true*/
/*global $: false, wgNamespaceNumber: false, wgAction: false, mw: false,
  wgScriptPath: false, wgPageContentLanguage: false, window: false */

if (window.globalTranslatorConfigs === undefined) {
    var globalTranslatorConfigs = {
        'homeWiki': window.homeWiki,
        'fromLang': window.fromLang,
        'translatorBarFormat': window.translatorBarFormat,
        'templateTranslatorText': window.templateTranslatorText,
        'removeLinksAliasesText': window.removeLinksAliasesText,
        'doneText': window.doneText
    };
}

var translatorConfigs = {
	'homeWiki': 'ar',
    'fromLang': 'en',
    'translatorBarFormat': '$1ترجم$2 الوصلات $4&nbsp;⇒&nbsp;$3',
    'templateTranslatorText': 'ترجم القوالب',
    'removeLinksAliasesText': 'أخف عناوين الوصلات',
    'doneText': 'تم',
    'enableTemplateTranslation': true,
    'removeLinksAliases': true,
    'enableNeedingShow': false,
    'name': 'اسم الصفحة',
    'interwikiCount': 'عدد وصلات اللغات فيها',
    'linkedTo': 'عدد الوصلات فيها',
    'listOfUnavailablePagesOn': 'الصفحات غير الموجودة في '
};

$.extend(translatorConfigs, globalTranslatorConfigs);

// getting the last translator preference from the cookie
if ($.cookie('homeWiki') !== null) {
    translatorConfigs.homeWiki = $.cookie('homeWiki');
}

if ($.cookie('fromLang') !== null) {
    translatorConfigs.fromLang = $.cookie('fromLang');
}
//

// Regexp.escape() from: http://80.68.89.23/2006/Jan/20/escape/
RegExp.escape = function (text) {
    'use strict';
    return text.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
};

function Translator() {
    'use strict';

    var translationTextArea,
        progressCount,
        itemsCount,
        ajaxUrl;

    function getOrigin() {
        var result = window.location.protocol + '//' + window.location.host;
        if (window.location.port !== '') {
            result = result + ':' + window.location.port;
        }
        return result;
    }

    function getOriginOfWikiLang(lang) {
        return getOrigin().replace(wgPageContentLanguage, lang);
    }

    function setAjaxUrl() {
        var tailOfApiUrl = '/api.php?action=query&prop=langlinks&redirects=&format=json&lllimit=500&titles=';
        if (translatorConfigs.enableNeedingShow === true) {
            tailOfApiUrl = '/api.php?action=query&prop=langlinks|links&redirects=&format=json&pllimit=500&lllimit=500&titles=';
        }
        ajaxUrl = getOriginOfWikiLang(translatorConfigs.fromLang) + wgScriptPath + tailOfApiUrl;
    }

    function getSelectedTextLinks() {
        // borrowed from: http://stackoverflow.com/questions/4220478 :)
        var selection,
            selectionAncestor,
            range,
            allWithinRangeParent,
            allSelected,
            i,
            el;

        // if `window.getSelection` is not defined (on IE) return nothing.
        if (window.getSelection === undefined) {
            return [];
        }
        selection = window.getSelection();

        // if nothing is selected, return empty array
        if (selection.isCollapsed) {
            return [];
        }

        range = selection.getRangeAt(0);
        selectionAncestor = range.commonAncestorContainer;
        if (selectionAncestor.getElementsByTagName === undefined) { // if it is not a formal HTML selection
            return [];
        }
        allWithinRangeParent = selectionAncestor.getElementsByTagName('a');

        allSelected = [];
        for (i = 0; (el = allWithinRangeParent[i]) !== undefined; i += 1) {
            // The second parameter says to include the element 
            // even if it's not fully selected
            if (selection.containsNode(el, true)) {
                allSelected.push(el);
            }
        }
        return allSelected;
    }


    /*jslint unparam: true*/ // I don't want use key parameter in closures!
    function increaseProgressCount() {
        progressCount = progressCount + 1;
        $('#translatorProgress').attr('value', progressCount);

        if (progressCount === itemsCount) {
            $('#translatorProgress').hide('slow');
            $('#translatorStatus').css('font-weight', 'bold').text(translatorConfigs.doneText).show('slow');
            $( ".translatorAddedcontent" ).prev().css( "color", "lightblue" );
            if (translatorConfigs.enableNeedingShow) {
                var links = [],
                    result,
                    linksCount,
                    titleExistance = {},
                    title;
                $('.translatorNeededLink').each(function (k, v) {
                    title = $(v).attr('data-title');
                    if (titleExistance[title] === true) {
                        return;
                    }
                    titleExistance[title] = true;
                    linksCount = $(v).attr('data-links-to-count');
                    if (parseInt(linksCount, 10) === 500) {
                        linksCount = '500+';
                    }
                    links.push([title, parseInt($(v).attr('data-interwikis'), 10), linksCount]);
                });
                links = links.sort(function (x, y) { return y[1] - x[1]; });
                result = '<table class="wikitable sortable" ><tr><th>' + translatorConfigs.name + '</th><th>' + translatorConfigs.interwikiCount + '</th><th>' + translatorConfigs.linkedTo + '</th></tr>' + links.map(function (x) { return '<tr><td style="unicode-bidi: plaintext;"><a href="' + x[0] + '">' + x[0] + '</a></td><td>' + x[1] + '</td><td>' + x[2] + '</tr>'; }).join('') + '</table>';
                $('#translatorPlusContainer').remove();
                $('<li style="line-height: 1.25;" id="translatorPlusContainer">' + translatorConfigs.listOfUnavailablePagesOn + ' ' + translatorConfigs.homeWiki + '.wiki:\n<div style="white-space: pre-line;">' + result + '</div></li>').appendTo('#translatorBar');
            }
        }
    }

    function queryTranslationFromData(data) {
        var languageLinks,
            linksToCount = 0,
            translation;

        if (data.query === undefined || data.query.pages === undefined) {
            return null;
        }
        $.each(data.query.pages, function (key, value) { // for retrieving first object index
            languageLinks = value.langlinks;
            if (value.links !== undefined) {
                linksToCount = value.links.length;
            }
        });
        if (languageLinks === undefined) {
            return null;
        }
        $.each(languageLinks, function (key, value) { // we can also use .filter here
            if (value.lang === translatorConfigs.homeWiki) {
                translation = value['*'];
            }
        });
        return {
            translation: translation,
            linksToCount: linksToCount,
            interwikis: languageLinks.length
        };
    }
    /*jslint unparam: false*/

    function commonAjaxRunner(title, translatorFunction) {
        $.ajax({
            url: ajaxUrl + encodeURIComponent(title),
            complete: function () {
                increaseProgressCount();
            },
            success: function (data) {
                var translation = queryTranslationFromData(data);
                if (translation !== null) {
                    translatorFunction(translation);
                }
            },
            dataType: 'jsonp'
        });
    }

    function addTranslationToNode(node, translation) {
        if (translation.translation !== undefined) {
            node.after('<span class="translatorAddedcontent">' + '(<a href="' + getOriginOfWikiLang(translatorConfigs.homeWiki) + mw.util.getUrl(translation.translation) + '">' + translation.translation + '</a>)</span>');
        } else if (translatorConfigs.enableNeedingShow === true) {
            node.after('<span class="translatorAddedcontent">(<span style="color: red;" class="translatorNeededLink" data-title="' + node.attr('title') + '" data-interwikis="' + translation.interwikis + '" data-links-to-count="' + translation.linksToCount + '">' + translation.interwikis + '</span>)</span>');
        }
    }

    function translateFromLanguageLinkNode(title, node) {
        commonAjaxRunner(title, function (translation) {
            addTranslationToNode(node, translation);
        });
    }

    // for [[Link]]s in textareas
    function addTranslationToTextareaLink(title, translation) {
        translationTextArea.val(translationTextArea.val().replace(
            new RegExp('(\\[\\[:?)' + RegExp.escape(title) + '((?:\\|[^\\]]*)?)(\\]\\])'),
            '$1' + translation + (translatorConfigs.removeLinksAliases ? '' : '$2') + '$3'
        ));
    }

    function translateFromLanguageLinks(title) {
        commonAjaxRunner(title, function (translation) {
            if (translation.translation !== undefined) {
                addTranslationToTextareaLink(title, translation.translation);
            }
        });
    }

    // for {{TemplateLink}}s in textareas
    function addTranslationToTextareaTemplateLink(title, translation) {
        translationTextArea.val(translationTextArea.val().replace(
            new RegExp('(\\{\\{\\s*(?:[Tt]emplate:)?)' + RegExp.escape(title) + '([\\n\\|\\}])'),
            '$1' + translation + '$2'
        ));
    }

    function translateFromLanguageTemplateLinks(title) {
        commonAjaxRunner('Template:' + title, function (translation) {
            if (translation.translation !== undefined) {
                addTranslationToTextareaTemplateLink(title, translation.translation.replace(/^.*?:/, ''));
            }
        });
    }

    function parseUrl(url) {
        if (url === undefined) {
            return undefined;
        }
        var match = url.match(/\/wiki\/([^#]*)/);
        if (match === null) {
            match = url.match(/\/w\/index\.php\?title=([^&#]*).*redlink=1/);
        }

        if (match !== null) {
            return decodeURI(match[1]); // returns () matched text
        }
        return undefined;
    }

    function getLinkTitle(link) { // previously it was link.attr("title")
        return parseUrl(link.attr('href'));
    }

    this.run = function () {
        setAjaxUrl();
        progressCount = 0;
        itemsCount = 0;
        $('#translatorStatus').hide(0);
        $('#translatorProgress').removeAttr('max').removeAttr('value');
        $('.translatorAddedcontent').remove();

        var links,
            templates,
            i,
            title;

        if (mw.config.get('wgAction') === 'view' || mw.config.get('wgAction') === 'purge' || mw.config.get('wgAction') === 'historysubmit') {
            links = getSelectedTextLinks();
            if (links.length === 0) {
                links = $('#bodyContent a');
            }
            $(links).filter('a').each(function () {
                var iter = $(this),
                    title = getLinkTitle(iter);
                if (title !== undefined) {
                    itemsCount = itemsCount + 1;
                    translateFromLanguageLinkNode(title, iter);
                }
            });
            $('#translatorProgress').show().attr('max', itemsCount);
        } else if (mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit') {
            $('#wpTextbox2').remove(); // remove translation textarea if exists

            if (translatorConfigs.fromLang === wgPageContentLanguage) {
                translationTextArea = $('#wpTextbox1').clone().attr({
                    'id': 'wpTextbox2'
                }).css({ // new color for translation textarea
                    'background-color': 'whitesmoke'
                }).val($('#wpTextbox1').val()); // this something that clone must do
                $('#wpTextbox1').before(translationTextArea); // put translation textarea before old
            } else {
                translationTextArea = $('#wpTextbox1');
            }

            // for links
            links = translationTextArea.val().match(/\[\[.*?\]\]/g);
            templates = translationTextArea.val().match(/\{\{.*?[\n\|\}]/g);

            itemsCount = -1;
            if (links !== null) {
                for (i = 0; i < links.length; i = i + 1) { // equals with <code>for (i in matched)</code>
                    title = links[i].replace(/\[\[:?([^\]\|]*)\|?.*?\]\]/g, "$1");
                    translateFromLanguageLinks(title);
                }

                if (itemsCount === -1) {
                    itemsCount = 0;
                }
                itemsCount = itemsCount + links.length;
            }

            if (templates !== null && translatorConfigs.enableTemplateTranslation === true) {
                for (i = 0; i < templates.length; i = i + 1) { // equals with <code>for (i in matched)</code>
                    title = templates[i].replace(/\{\{\s*(?:[Tt]emplate:)?(.*)\s*[\n\|\}]/g, '$1');
                    translateFromLanguageTemplateLinks(title);
                }

                if (itemsCount === -1) {
                    itemsCount = 0;
                }
                itemsCount = itemsCount + templates.length;
            }

            if (itemsCount !== -1) {
                $('#translatorProgress').show().attr('max', itemsCount);
            }
        }
    };
}

var translator = new Translator();
$(function () {
    "use strict";

    function initializeEditorFor(forEditable, inputForEditable, setVariableClosure) {
        $(forEditable).click(function (event) {
            event.preventDefault();
            $(forEditable).hide();
            $(inputForEditable).css('width', '2em').show().val($(forEditable).text());
        });

        $(inputForEditable).keyup(function (event) {
            var selectedLanugage = $(this).val();
            if (event.keyCode === 13) {
                $(this).focusout(); // on enter
            } else if (event.keyCode === 27) {
                $(forEditable).show(); // on escape
                $(inputForEditable).hide().val(selectedLanugage);
            }
        }).focusout(function () {
            var selectedLanugage = $(this).val();
            if (/...?/.test(selectedLanugage)) {
                setVariableClosure(selectedLanugage);
                $(forEditable).html(selectedLanugage);
            }
            $(forEditable).show();
            $(inputForEditable).hide();
        });
    }

    $('#translatorBar').remove();
    var html = '<li style="unicode-bidi: normal;margin-inline-end: 1em;list-style-type: none;display: inline-block; direction: rtl; margin-top: 0.5em; color: grey; letter-spacing: 0.5px;" id="translatorBar">' + translatorConfigs.translatorBarFormat;
    if (mw.config.get('wgAction') === "edit" || mw.config.get('wgAction') === "submit") {
        html = html + ' <input type="checkbox" name="enableTemplateTranslation" id="enableTemplateTranslation"><label for="enableTemplateTranslation">' + translatorConfigs.templateTranslatorText + '</label>';
        html = html + ' <input type="checkbox" name="removeLinksAliases" id="removeLinksAliases"><label for="removeLinksAliases">' + translatorConfigs.removeLinksAliasesText + '</label>';
    }

    html = html + '<span id="translatorStatus"></span><progress id="translatorProgress" style="display: none;font-size:5px;margin-inline-start:1em">يجري...</progress></li>';

    html = html.replace('$1', '(<a title="البحث أو الترجمة في غوغل" id="translator-equ" href="#"">…</a><span id="translator-equ-links"></span>) <a id="translator-button" href="#"> ');
    html = html.replace('$2', '</a><span> (<a id="translator-plus" title="المقالات الناقصة في العربية" href="#">-</a>)</span>');
    html = html.replace('$3', '<a id="translator-from" href="#">' + translatorConfigs.fromLang + '</a><input style="display: none" id="translator-from-input">');
    html = html.replace('$4', '<a id="translator-to" href="#">' + translatorConfigs.homeWiki + '</a><input style="display: none" id="translator-to-input">');
    if (mw.config.get('skin') == 'minerva') {
    	    		  $('#bodyContent').prepend(html);

} else {
	    			$('#p-tb > div > ul').append(html);	

}
 
    	

    

    $('#translator-button').click(function (event) {
        event.preventDefault();
        translatorConfigs.enableNeedingShow = false;
        translator.run();
    });
    
    $('#translator-equ').click(function (event) {
        event.preventDefault();
        $('#translator-equ-links').html('<a target="_blank" href="//translate.google.com/translate_t?sl=' + translatorConfigs.fromLang + '&tl=' + translatorConfigs.homeWiki + '&q=' + mw.config.get('wgTitle') + '">جوجل: ترجمة</a> | <a target="_blank" href=\'//www.google.com/search?q="' + mw.config.get('wgTitle') + '"&lr=lang_' + translatorConfigs.homeWiki + '\'>بحث باللغة الهدف</a>');
    });

    $('#translator-plus').click(function (event) {
        event.preventDefault();
        translatorConfigs.enableNeedingShow = true;
        translator.run();
    });

    initializeEditorFor('#translator-to', '#translator-to-input', function (value) {
        translatorConfigs.homeWiki = value;
        $.cookie("homeWiki", value);
    });

    initializeEditorFor('#translator-from', '#translator-from-input', function (value) {
        translatorConfigs.fromLang = value;
        $.cookie("fromLang", value);
    });

    $('#enableTemplateTranslation').attr('checked', translatorConfigs.enableTemplateTranslation).click(function () {
        translatorConfigs.enableTemplateTranslation = this.checked;
    });

    $('#removeLinksAliases').attr('checked', translatorConfigs.removeLinksAliases).click(function () {
        translatorConfigs.removeLinksAliases = this.checked;
    });
});

mw.util.addCSS("#translator-equ, #translator-plus {font-family: monospace;} .translatorAddedcontent {font-size: small; padding-left: 5px; unicode-bidi: plaintext;font-family: serif;    color: red;} #translatorStatus {margin-right:1em}");