User:NatigKrolik/merge 1.js

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
// ENABLE IT FROM YOUR PREFERENCES: www.wikidata.org/wiki/Special:Preferences#mw-prefsection-gadgets
/*!
 * merge.js - Script to merge Wikidata items
 * @author User:Ebraminio <ebrahim -at- gnu.org>
 * @contributors User:Ebraminio, User:Ricordisamoa
 * @license CC-Zero
 */
/*jslint browser: true, regexp: true, indent: 2, unparam: true*/
/*jshint unused: false*/
/*global jQuery, mediaWiki, wikibase*/
// See also: MediaWiki:Gadget-EmptyDetect.js and MediaWiki:Gadget-RfDHelper.js
//<nowiki>
(function ($, mw) {
  'use strict';
  var messages, itemId = mw.config.get('wbEntityId');

  messages = (function () {
    var translations = {
      'en': {
        close: 'Close',
        closeDialog: 'Close this dialog without merging the items',
        confilictMessage: 'A conflict detected on ',
        confilictWithMessage: 'with',
        deleteOption: 'Try to automatically delete extra items after merge (only admins)',
        deleting: 'Deleting...',
        deletingItem: 'Deleting the item...',
        itemDeleterAccessError: 'You aren\'t an administrator',
        itemIdInvalid: 'The item\'s id is not defined',
        loadingMergeDestination: 'Loading merge destination...',
        lowestQid: 'Always merge into the item with lowest Qid',
        merge: 'Merge',
        mergePendingNotification: 'Merge.js has been started.<br/>Now you can focus your browser on the other item.',
        mergeProcess: 'Process the merge now',
        mergeThisItem: 'Merge this item',
        mergeWithInput: 'Merge it with:',
        mergeWithProgress: 'Merge it with...',
        mergeWizard: 'Merge Wizard',
        mergingClaim: 'Merging claims...',
        movingClaim: 'Moving claims...',
        movingSitelink: 'Moving site links...',
        pleaseWait: 'Please wait...',
        postpone: 'Postpone',
        postponeTitle: 'Store this item\'s id and postpone the merge',
        processPostponed: 'process the postponed merge',
        requestDeletion: 'Request deletion for extra items on RfD',
        requestingDeletion: 'Requesting deletion...',
        requestingStreamDeletion: 'Requesting Stream Deletion...',
        sendingToRfd: 'Sending to RfD...',
        streamDelete: 'Request $1StreamDeletion$2 for this item (experimental)',
        unwatchOption: 'Remove merged items from your watchlist (if watched)',
        unwatching: 'Removing from watch list...'
      },
      'cs': {
        close: 'Zavřít',
        closeDialog: 'Zavřít toto okno bez sloučení položek',
        confilictMessage: 'Detekován konflikt v',
        confilictWithMessage: 's',
        deleteOption: 'Pokusit se automaticky smazat extra položky po sloučení (pouze správci)',
        deleting: 'Mažu...',
        deletingItem: 'Mažu položku...',
        itemDeleterAccessError: 'Nejste správce',
        itemIdInvalid: 'Není zadáno id položky',
        loadingMergeDestination : 'Načítám výsledek sloučení...',
        lowestQid: 'Vždy sloučit do položky s nižším číslem',
        merge: 'Sloučit',
        mergePendingNotification: 'Skript Merge.js byl aktivován.<br/>Nyní můžete ve vašem prohlížeči přejít na jinou položku.',
        mergeProcess: 'Provést nyní sloučení',
        mergeThisItem: 'Sloučit položku',
        mergeWithInput: 'Sloučit s:',
        mergeWithProgress: 'Sloučit s...',
        mergeWizard: 'Nástroj pro slučování',
        mergingClaim: 'Slučuji tvrzení...',
        movingClaim: 'Přesunuji tvrzení...',
        movingSitelink: 'Přesunuji odkazy...',
        pleaseWait: 'Prosím čekejte...',
        postpone: 'Odložit',
        postponeTitle: 'Uložit id položky a odložit sloučení',
        processPostponed: 'provést odložené sloučení',
        requestDeletion: 'Požádat o smazání extra položek na RfD',
        requestingDeletion: 'Žádám o smazání...',
        requestingStreamDeletion: 'Žádám o smazání (StreamDelete)...',
        sendingToRfd: 'Posílám na RfD...',
        streamDelete: 'Požádat o $1StreamDelete$2 (experimentální)',
        unwatchOption: 'Odstranit slučované položky ze sledovaných stránek (jsou-li sledovány)',
        unwatching: 'Odstraňuji ze sledovaných stránek...'
      },
      'de': {
        close: 'Schließen',
        closeDialog: 'Schließen ohne Änderung',
        confilictMessage: 'Ein Konflikt wurde erkannt bei ',
        confilictWithMessage: 'mit',
        deleteOption: 'Lösche übrige Datenelemente nach dem Zusammenlegen (nur für Admins)',
        deleting: 'Lösche…',
        deletingItem: 'Lösche das Datenelement…',
        itemDeleterAccessError: 'Du musst Administrator sein, um Datenelemente zu löschen.',
        itemIdInvalid: 'Die Nummer des Datenelementes ist nicht definiert',
        loadingMergeDestination: 'Lade zusammengelegtes Datenelement…',
        lowestQid: 'Immer in das Datenelement mit der niedrigeren Q-Nummer zusammenlegen',
        merge: 'Zusammenlegen',
        mergePendingNotification: 'Merge.js wurde gestartet.<br/>Jetzt kannst du das andere Datenelement öffnen.',
        mergeProcess: 'Starte das Zusammenlegen jetzt',
        mergeThisItem: 'Lege das Datenelement zusammen',
        mergeWithInput: 'Zusammenlegen mit:',
        mergeWithProgress: 'Zusammenlegen mit…',
        mergeWizard: 'Assistent zum Zusammenlegen',
        mergingClaim: 'Lege Aussagen zusammen…',
        movingClaim: 'Verschiebe Aussagen…',
        movingSitelink: 'Verschiebe Wikipedia-Links…',
        pleaseWait: 'Bitte warte…',
        postpone: 'Verschieben',
        postponeTitle: 'Speichere die Nummer des Datenelementes und mach es zum Ziel einer Zusammenlegung',
        processPostponed: 'Starte das Zusammenlegen in das andere Datenelement',
        requestDeletion: 'Stelle Löschantrag für übrig gebliebene Datenelemente auf RfD',
        requestingDeletion: 'Stelle Löschantrag…',
        requestingStreamDeletion: 'Beantrage die Löschung bei StreamDelete…',
        sendingToRfd: 'Stelle Löschantrag auf RfD…',
        streamDelete: 'Beantrage die Löschung bei $1StreamDelete$2 (experimentell)',
        unwatchOption: 'Entferne zusammengelegte Datenelemente von der Beobachtungsliste (wenn beobachtet)',
        unwatching: 'Entferne von Beobachtungsliste…'
      },
      'es': {
        close: 'Cerrar',
        closeDialog: 'Cierra este diálogo sin fusionar los elementos',
        confilictMessage: 'Un conflicto detectado en ',
        confilictWithMessage: 'con',
        deleteOption: 'Probar a borrar automáticamente los elementos vacíos después de la fusión (solo administradores)',
        deleting: 'Borrando...',
        deletingItem: 'Borrando el elemento...',
        itemDeleterAccessError: 'No eres administrador/a',
        itemIdInvalid: 'El id del elemento no está definido',
        loadingMergeDestination: 'Cargando el destino de la fusión...',
        lowestQid: 'Fusionar siempre el elemento con el menor número de Qid (identificador de Q)',
        merge: 'Fusionar',
        mergePendingNotification: 'Merge.js empezó.<br/>Ahora puedes enfocar tu navegador en el otro elemento',
        mergeProcess: 'Proceder a la fusión ahora',
        mergeThisItem: 'Fusionar este elemento',
        mergeWithInput: 'Fusionarlo con:',
        mergeWithProgress: 'Fusionarlo con...',
        mergeWizard: 'Herramienta de fusión',
        mergingClaim: 'Fusionando las afirmaciones...',
        movingClaim: 'Moviendo las afirmaciones...',
        movingSitelink: 'Moviendo los enlaces de sitio...',
        pleaseWait: 'Por favor, espera...',
        postpone: 'Posponer',
        postponeTitle: 'Guardar el id de este elemento y posponer la fusión',
        processPostponed: 'procesar la fusión aplazada',
        requestDeletion: 'Solicitar el borrado de los elementos vacíos en RfD (Solicitud de borrador)',
        requestingDeletion: 'Solicitando eliminación...',
        requestingStreamDeletion: 'Solicitando la eliminación Stream...',
        sendingToRfd: 'Enviando a RfD...',
        streamDelete: 'Solicitar $1StreamDeletion$2 para este elemento (experimental)',
        unwatchOption: 'Eliminar los elementos fusionados de tu lista de seguimiento (si están)',
        unwatching: 'Eliminando de la lista de seguimiento...'
      },
      'fa': {
        close: 'بستن',
        closeDialog: 'بستن پنجره بدون ادغام آیتم\u200cها',
        confilictMessage: 'تداخل در ',
        confilictWithMessage: 'با',
        deleteOption: 'آیتم\u200cهای خالی را بعد از ادغام حذف کن (فقط برای مدیران)',
        deleting: 'در حال حذف\u200cکردن...',
        deletingItem: 'در حال حذف آیتم ...',
        itemIdInvalid: 'شناسهٔ آیتم تعریف نشده\u200cاست',
        loadingMergeDestination: 'بارگیری مقصد ادغام...',
        lowestQid: 'همیشه ادغام در شماره شناسهٔ کمتر انجام گیرد',
        merge: 'ادغام',
        mergePendingNotification: 'ابزار ادغام فعال شد<br/>هم\u200cاکنون می\u200cتوانید به صفحهٔ آیتم دیگر برای ادغام بروید.',
        mergeProcess: 'انجام دادن ادغام',
        mergeThisItem: 'ادغام این آیتم',
        mergeWithInput: 'ادغام\u200cکردن با:',
        mergeWithProgress: 'ادغام\u200cکردن با...',
        mergeWizard: 'ابزار ادغام',
        mergingClaim: 'ادغام اظهارات...',
        movingClaim: 'انتقال اظهارات...',
        movingSitelink: 'انتقال پیوند وب\u200cگاه\u200cها...',
        pleaseWait: 'صبر کنید ...',
        postpone: 'به تأخیر انداختن',
        postponeTitle: 'ذخیرهٔ شناسهٔ آیتم و به تاخیر انداختن ادغام',
        processPostponed: 'عمل به تأخیر انداختن ادغام انجام شد',
        requestDeletion: 'درخواست حذف برای آیتم\u200cهای خالی شده',
        requestText: 'درخواست $1',
        requestingDeletion: 'درحال درخواست حذف ...',
        requestingStreamDeletion: 'درحال ارسال درخواست حذف نمایشی...',
        sendingToRfd: 'ارسال برای درخواست حذف...',
        streamDelete: 'درخواست $1StreamDeletion$2 برای این آیتم (آزمایشی)',
        unwatchOption: 'حذف آیتم\u200cهای ادغام شده از فهرست پی\u200cگیری\u200cها',
        unwatching: 'حذف از پیگیری\u200cها...'
      },
      'fr': {
        close: 'Fermer',
        closeDialog: 'Fermer cette fenêtre sans fusionner les éléments',
        confilictMessage: 'Un conflit a été détecté sur ',
        confilictWithMessage: 'avec',
        deleteOption: 'Essayer de supprimer automatiquement les éléments en trop après la fusion (administrateurs seulement)',
        deleting: 'Suppression...',
        deletingItem: 'Suppression de l\'entrée...',
        itemDeleterAccessError: 'Vous n\'êtes pas un administrateur',
        itemIdInvalid: 'L\'identifiant de l\'élément n\'est pas défini',
        loadingMergeDestination: 'Chargement de la destination de fusion...',
        lowestQid: 'Toujours fusionner dans l\'élément avec le plus petit Qid',
        merge: 'Fusionner',
        mergePendingNotification: 'Merge.js a commencé.<br/>Vous pouvez maintenant consulter un autre élément.',
        mergeProcess: 'Procéder à la fusion maintenant',
        mergeThisItem: 'Fusionner cet élément',
        mergeWithInput: 'Fusionner avec :',
        mergeWithProgress: 'Fusionner avec...',
        mergeWizard: 'Outil de fusion',
        mergingClaim: 'Fusion des réclamations...',
        movingClaim: 'Déplacement des réclamations...',
        movingSitelink: 'Déplacement des liens de site...',
        pleaseWait: 'Attendez...',
        postpone: 'Repousser à plus tard',
        postponeTitle: 'Stocker cet identifiant et repousser à plus tard la fusion',
        processPostponed: 'procéder à la fusion repoussée',
        requestDeletion: 'Demander la suppression des éléments en trop dans les demandes de suppression',
        requestingDeletion: 'Demande de la suppression...',
        requestingStreamDeletion: 'Demande de la suppression de flux...',
        sendingToRfd: 'Envoi à RfD...',
        streamDelete: 'Demander une $1StreamDeletion$2 pour cet élément (expérimental)',
        unwatchOption: 'Retirer les éléments supprimés de votre liste de suivi (s\'ils étaient suivis)',
        unwatching: 'Retrait de la liste de suivi...'
      },
      'gl': {
        close: 'Pechar',
        closeDialog: 'Pecha este diálogo sen fusionar os elementos',
        confilictMessage: 'Un conflito detectado en ',
        confilictWithMessage: 'con',
        deleteOption: 'Probar a borrar automaticamente os elementos baleiros despois da fusión (só administradores)',
        deleting: 'Borrando...',
        deletingItem: 'Borrando o elemento...',
        itemDeleterAccessError: 'Non es administrador/a',
        itemIdInvalid: 'O id do elemento non está definido',
        loadingMergeDestination: 'Cargando o destino da fusión...',
        lowestQid: 'Fusionar sempre o elemento co menor número de Qid (identificador de Q)',
        merge: 'Fusionar',
        mergePendingNotification: 'Merge.js comezou.<br/>Agora podes enfocar o teu navegador no outro elemento',
        mergeProcess: 'Proceder á fusión agora',
        mergeThisItem: 'Fusionar este elemento',
        mergeWithInput: 'Fusionalo con:',
        mergeWithProgress: 'Fusionalo con...',
        mergeWizard: 'Ferramenta de fusión',
        mergingClaim: 'Fusionando as afirmacións...',
        movingClaim: 'Movendo as afirmacións...',
        movingSitelink: 'Movendo as ligazóns de sitio...',
        pleaseWait: 'Por favor, espera...',
        postpone: 'Pospoñer',
        postponeTitle: 'Gardar o id deste elemento e pospor a fusión',
        processPostponed: 'procesar a fusión aprazada',
        requestDeletion: 'Solicitar o borrado dos elementos baleiros en RfD (Solicitude de borrador)',
        requestingDeletion: 'Solicitando eliminación...',
        requestingStreamDeletion: 'Solicitando a eliminación Stream...',
        sendingToRfd: 'Enviando a RfD...',
        streamDelete: 'Solicitar $1StreamDeletion$2 para este elemento (experimental)',
        unwatchOption: 'Eliminar os elementos fusionados da túa lista de vixilancia (se están)',
        unwatching: 'Eliminando da lista de vixilancia...'
      },
      'gu': {
        close: 'બંધ કરો',
        closeDialog: 'લેખોને વિલીન કર્યા સિવાય આ સંદેશ બંધ કરો',
        confilictMessage: 'પર એક અથડામણ મળેલ છે',
        confilictWithMessage: 'સાથે',
        deleteOption: 'વિલીન કર્યા બાદ વધારાના લેખો સ્વચલિત રીતે દૂર કરવા પ્રયાસ કરો (ફક્ત પ્રબંધકો)',
        deleting: 'રદ થઈ રહ્યું છે...',
        deletingItem: 'લેખ રદ કરાઈ રહ્યો છે...',
        itemDeleterAccessError: 'તમે પ્રબંધક નથી',
        itemIdInvalid: 'આ લેખની ઓળખ અપાઈ નથી',
        loadingMergeDestination: 'વિલિન કરેલ લક્ષ્યાંક લાવાય રહ્યું છે...',
        lowestQid: 'હંમેશા સૌથી નીચા Q આંકડા સાથે લેખો વિલીન કરો',
        merge: 'વિલીનMerge',
        mergePendingNotification: 'Merge.js શરૂ થઈ ગયેલ છે.<br/> હવે તમે તમારું બ્રાઉઝર અન્ય લેખ પર કેન્દ્રિત કરી શકો છો.',
        mergeProcess: 'હમણા જ વિલિનીકરણની પ્રક્રિયા કરો કરો',
        mergeThisItem: 'આ લેખ વિલિન કરો',
        mergeWithInput: 'તેને સાથે વિલિન કરો:',
        mergeWithProgress: 'તેને સાથે વિલિન કરો...',
        mergeWizard: 'વિલિન વિઝાર્ડ',
        mergingClaim: 'દાવાઓ વિલિન કરાય છે...',
        movingClaim: 'દાવાઓ ખસેડાય છે...',
        movingSitelink: 'જાળસ્થળની કડીઓ ખસેડાઈ રહી છે...',
        pleaseWait: 'મહેરબાની કરીને રાહ જુઓ...',
        postpone: 'મુલતવી રાખોPostpone',
        postponeTitle: 'આ લેખની ઓળખ સાચવો અને વિલિનીકરણ મુલતવી રાખો',
        processPostponed: 'મુલતવી રાખેલ વિલિનિકરણ શરૂ કરો',
        requestDeletion: 'રદ કરવા માટેની વિનંતી ખાતે વધારાના લેખો દૂર કરવા વિનંતી કરો',
        requestingDeletion: 'રદ કરવા માટે વિનંતી કરાઈ રહી છે...',
        requestingStreamDeletion: 'સ્ટ્રિમ રદ કરવા વિનંતી કરાઈ રહી છે...',
        sendingToRfd: 'રદ કરવા માટે વિનંતી ખાતે મોકલાઈ રહ્યું છે...',
        streamDelete: 'આ લેખ માટે $1StreamDeletion$2 વિનંતી કરો (પ્રાયોગિક)',
        unwatchOption: 'વિલિન કરેલ લેખો તમારી ધ્યાનસૂચિમાંથી હટાવો (જો ધ્યાનસૂચિમાં હોય તો)',
        unwatching: 'ધ્યાનસૂચિમાંથી હટાવાય રહ્યું છે...'
      },
      'id': {
        close: 'Tutup',
        closeDialog: 'Tutup dialog ini tanpa menggabungkan item',
        confilictMessage: 'Ada konflik terdeteksi pada ',
        confilictWithMessage: 'dengan',
        deleteOption: 'Secara otomatis menghapus item tambahan setelah penggabungan (hanya admin)',
        deleting: 'Menghapus...',
        deletingItem: 'menghapus item...',
        itemDeleterAccessError: 'Anda bukan pengurus',
        itemIdInvalid: 'Item belum ditentukan',
        loadingMergeDestination: 'Loading tujuan penggabungan...',
        lowestQid: 'Selalu gabungkan dengan Qid item terendah',
        merge: 'Gabung',
        mergePendingNotification: 'Merge.js dimulai.<br/>Sekarang Anda dapat fokus pada item lain.',
        mergeProcess: 'Lakukan penggabungan',
        mergeThisItem: 'Gabungkan item ini',
        mergeWithInput: 'Gabung dengan:',
        mergeWithProgress: 'Gabungkan',
        mergeWizard: 'Peralatan penggabungan',
        mergingClaim: 'Gabungkan klaim...',
        movingClaim: 'Pindahkan klaim...',
        movingSitelink: 'Pindahkan interwiki...',
        pleaseWait: 'Mohon tunggu sebentar...',
        postpone: 'Tunda',
        postponeTitle: 'Simpan item dan tunda penggabungan',
        processPostponed: 'proses penggabungan yang ditunda',
        requestDeletion: 'Minta penghapusan pada item tambahan pada RfD',
        requestingDeletion: 'Permintaan penghapusan...',
        requestingStreamDeletion: 'Permintaan Penghapusan Stream...',
        sendingToRfd: 'Kirim ke RfD...',
        streamDelete: 'Permintaan $1Penghapusan Stream$2 pada item ini (eksperimental)',
        unwatchOption: 'Hapus item yang digabung dari pantauan (jika ada)',
        unwatching: 'Hapus dari daftar pantauan...'
      },
      'it': {
        close: 'Chiudi',
        closeDialog: 'Chiudi questa finestra senza unire gli elementi',
        confilictMessage: 'Rilevato un conflitto in ',
        confilictWithMessage: 'con',
        deleteOption: 'Cancella automaticamente gli elementi svuotati dopo l\'unione (solo amministratori)',
        deleting: 'Cancellazione...',
        deletingItem: 'Cancellazione dell\'elemento...',
        itemDeleterAccessError: 'Non sei un amministratore!',
        itemIdInvalid: 'Il numero Q dell\'elemento non è definito',
        loadingMergeDestination: 'Caricamento della destinazione...',
        lowestQid: 'Unisci sempre con l\'elemento col numero Q più piccolo',
        merge: 'Unione',
        mergePendingNotification: 'Merge.js è avviato.<br/>Adesso vai sulla pagina dell\'altro elemento.',
        mergeProcess: 'Effettua l\'unione adesso',
        mergeThisItem: 'Unisci questo elemento',
        mergeWithInput: 'Unisci con:',
        mergeWithProgress: 'Unione con l\'elemento...',
        mergeWizard: 'Unione guidata',
        mergingClaim: 'Unione delle dichiarazioni...',
        movingClaim: 'Trasferimento delle dichiarazioni...',
        movingSitelink: 'Trasferimento dei collegamenti linguistici...',
        pleaseWait: 'Aspetta...',
        postpone: 'Rimanda a dopo',
        postponeTitle: 'Memorizza l\'id di questo elemento e rimanda a dopo l\'unione',
        processPostponed: 'Elabora l\'unione rimandata',
        requestDeletion: 'Richiedi la cancellazione degli elementi svuotati',
        requestingDeletion: 'Richiesta di cancellazione...',
        requestingStreamDeletion: 'Richiesta di cancellazione con Stream...',
        sendingToRfd: 'Inserimento fra le richieste di cancellazione...',
        streamDelete: 'Richiedi la $1Cancellazione in Stream$2 per questo elemento (sperimentale)',
        unwatchOption: 'Rimuovi gli elementi uniti dagli osservati speciali (se presente)',
        unwatching: 'Rimozione dagli osservati speciali...'
      },
      'ja': {
        close: '閉じる',
        closeDialog: '項目を統合せずにこのダイアログを閉じます',
        confilictMessage: '衝突が検出されました: ',
        confilictWithMessage: 'と',
        deleteOption: '統合後に余分な項目の自動的な削除を試みる(管理者のみ)',
        deleting: '削除中...',
        deletingItem: '項目の削除中...',
        itemDeleterAccessError: 'あなたは管理者ではありません',
        itemIdInvalid: 'その項目のIDは定義されていません',
        loadingMergeDestination: '統合先の読込中...',
        lowestQid: 'Qから始まるIDが小さい方の項目を必ず統合先に選ぶ',
        merge: '統合',
        mergePendingNotification: 'Merge.js が動き出しました。<br/>もうブラウザで他の項目に切り替えても大丈夫です。',
        mergeProcess: '統合をいま実行します',
        mergeThisItem: 'この項目を統合する',
        mergeWithInput: '統合相手:',
        mergeWithProgress: '2つの項目を統合',
        mergeWizard: '統合ウィザード',
        mergingClaim: '主張の統合中...',
        movingClaim: '主張の移動中...',
        movingSitelink: 'サイトリンクの移動中...',
        pleaseWait: 'お待ちください...',
        postpone: '延期',
        postponeTitle: 'この項目のIDを保存し、統合を延期します',
        processPostponed: '延期された統合を処理する',
        requestDeletion: '残った余分な項目を削除依頼に出す',
        requestingDeletion: '削除依頼中...',
        requestingStreamDeletion: 'Stream Deletion 依頼中...',
        sendingToRfd: '削除依頼への送信中...',
        streamDelete: 'この項目の $1StreamDeletion$2 を依頼する(実験的)',
        unwatchOption: '統合された項目をウォッチリストから除去する(ウォッチリストにある場合)',
        unwatching: 'ウォッチリストからの除去中...'
      },
      'ko': {
        close: '닫기',
        closeDialog: '항목을 합치지 않고 항목 병합 마법사를 닫습니다',
        confilictMessage: '항목 충돌 감지됨: ',
        confilictWithMessage: '와',
        deleteOption: '항목 병합을 완료한뒤 다른 항목을 삭제합니다(관리자만 가능)',
        deleting: '삭제중...',
        deletingItem: '항목 삭제중...',
        itemDeleterAccessError: '귀하는 관리자가 아닙니다.',
        itemIdInvalid: '아이템이 정의되지 않았습니다.',
        loadingMergeDestination: '병합한 내용을 불러오는 중입니다...',
        lowestQid: '항상 낮은 Qid를 가진 항목으로 병합합니다.',
        merge: '병합',
        mergePendingNotification: 'Merge.js 가 시작되었습니다.<br/>이제 다른 작업을 하셔도 됩니다.',
        mergeProcess: '병합을 시작합니다.',
        mergeThisItem: '이 항목을 병합',
        mergeWithInput: '이 항목과 병합할 다른 항목:',
        mergeWithProgress: '항목 병합 마법사',
        mergeWizard: '항목 병합 마법사',
        mergingClaim: '서술 병합중....',
        movingClaim: '서술 이동중...',
        movingSitelink: '사이트링크 이동중...',
        pleaseWait: '잠시만 기다리세요...',
        postpone: '연기',
        postponeTitle: '항목 번호 \'를 기억하고 병합을 일시 정지',
        processPostponed: '미뤄 둔 병합을 진행중',
        requestDeletion: '병합 후 자동으로 RFD에 삭제를 요청합니다.',
        requestingDeletion: '삭제 요청중...',
        requestingStreamDeletion: 'Stream Deletion 요청중...',
        sendingToRfd: 'RfD에 요청 중...',
        streamDelete: '이 항목을 $1StreamDeletion$2 요청합니다. (실험)',
        unwatchOption: '주시문서 목록에서 제거합니다 (주시중인 문서일 경우)',
        unwatching: '주시문서 목록에서 제거중...'
      },
      'lb': {
        close: 'Zoumaachen',
        closeDialog: 'Dësen Dialog zoumaachen ouni d\'Elementer ze fusionéieren',
        confilictMessage: 'Et gouf e Konflikt fonnt op ',
        confilictWithMessage: 'mat',
        deleteOption: 'Versiche fir zousätzlech Elementer no der Fusioun automatesch ze läschen (nëmmen Adminen)',
        deleting: 'Läschen...',
        deletingItem: 'D\'Element gëtt geläscht...',
        itemDeleterAccessError: 'Dir sidd keen Administrateur',
        itemIdInvalid: 'D\'Nummer vum Element ass net definéiert',
        loadingMergeDestination: 'D\'Zilsäit vun der Fusioun gëtt gelueden...',
        lowestQid: 'Ëmmer op dat Element fusionéieren dat déi niddregest Q-Nummer huet',
        merge: 'Fusionéieren',
        mergePendingNotification: 'Merge.js gouf gestart.<br/>Elo kënnt dir Iech an Ärem Browser op dat anert Element konzentréieren.',
        mergeProcess: 'Maacht d\'Fusioun elo',
        mergeThisItem: 'Fusionéiert dêst Element',
        mergeWithInput: 'Fusionéiert et mat:',
        mergeWithProgress: 'Fusionéiert et mat...',
        mergeWizard: 'Fusiouns-Wizard',
        mergingClaim: 'Reklammatioune fusionéieren...',
        movingClaim: 'Reklammatioune réckelen...',
        movingSitelink: 'Linken op site réckelen...',
        pleaseWait: 'Waard w.e.g....',
        postpone: 'Spéider maachen',
        postponeTitle: 'Dësem Element seng Nummer verhalen an d\'Fusioun op méi spéit verleeën',
        processPostponed: 'déi verluechte Fusioun elo maachen',
        requestDeletion: 'Läsche vun zousätzlechen Elementer per RfD ufroen',
        requestingDeletion: 'Läschen ufroen...',
        requestingStreamDeletion: '\'Stream-Läschen\' ufroen...',
        sendingToRfd: 'Un RfD schécken...',
        streamDelete: '$1StreamDeletion$2 firr dëst Element ufroen (experimentell)',
        unwatchOption: 'Fusionéiert lementer vun Ärer Iwwerwaachungslëscht erofhuelen (wa se iwwerwaacht sinn)',
        unwatching: 'Vun der Iwwerwaachungslëscht erofhuelen...'
      },
      'min': {
        close: 'Tutuik',
        closeDialog: 'Tutuik dialog ko tanpa manggabuangan item',
        confilictMessage: 'Ado konflik tadeteksi pado ',
        confilictWithMessage: 'jo',
        deleteOption: 'Sacaro otomatih mangapuih item tambahan sasudah panggabuangan (hanyo admin)',
        deleting: 'Mangapuih...',
        deletingItem: 'mangapuih item...',
        itemDeleterAccessError: 'Sanak indak panguruih',
        itemIdInvalid: 'Item alun ditentuan',
        loadingMergeDestination: 'Loading tujuan panggabuangan...',
        lowestQid: 'Salalu gabungan jo Qid item tarandah',
        merge: 'Gabuang',
        mergePendingNotification: 'Merge.js dimulai.<br/>Kini Sanak dapek fokus pado item lain.',
        mergeProcess: 'Lakukan panggabuangan',
        mergeThisItem: 'Gabuangkan item ko',
        mergeWithInput: 'Gabuang jo:',
        mergeWithProgress: 'Gabuangkan',
        mergeWizard: 'Pakakeh panggabuangan',
        mergingClaim: 'Gabuangkan klaim...',
        movingClaim: 'Pindahan klaim...',
        movingSitelink: 'Pindahan interwiki...',
        pleaseWait: 'Mohon tunggu sabanta...',
        postpone: 'Tunda',
        postponeTitle: 'Simpan item dan tunda panggabuangan',
        processPostponed: 'proses panggabuangan nan ditunda',
        requestDeletion: 'Minta pangapuihan pado item tambahan di RfD',
        requestingDeletion: 'Pamintaan pangapuihan...',
        requestingStreamDeletion: 'Pamintaan Pangapuihan Stream...',
        sendingToRfd: 'Kirim ka RfD...',
        streamDelete: 'Pamintaan $1Pangapuihan Stream$2 pado item ko (eksperimental)',
        unwatchOption: 'Hapuih item nan digabuang dari pantauan (kok ado)',
        unwatching: 'Hapuih dari daftar pantauan...'
      },
      'nl': {
        close: 'Sluiten',
        closeDialog: 'Sluit dit venster zonder de items samen te voegens',
        confilictMessage: 'Een conflict werd gedetecteerd op ',
        confilictWithMessage: 'met',
        deleteOption: 'Proberen automatisch de extra items te verwijderen na samenvoegen (alleen moderatoren)',
        deleting: 'Verwijderen...',
        deletingItem: 'Item aan het verwijderen...',
        itemDeleterAccessError: 'Je bent geen moderator',
        itemIdInvalid: 'ID van het item is niet gedefineerd',
        loadingMergeDestination: 'Bestemmingspagina samenvoeging laden...',
        lowestQid: 'Altijd samenvoegen in het item met het laagste Qid',
        merge: 'Samenvoegen',
        mergePendingNotification: 'Merge.js is gestart.<br/>Nu kan je jezelf focussen op het andere item.',
        mergeProcess: 'Samenvoeging nu uitvoeren',
        mergeThisItem: 'Dit item samenvoegen',
        mergeWithInput: 'Samenvoegen met:',
        mergeWithProgress: 'Samenvoegen met...',
        mergeWizard: 'Samenvoegingsassistent',
        mergingClaim: 'Claims verplaatsen...',
        movingClaim: 'Verklaringen verplaatsen...',
        movingSitelink: 'Siteverwijzingen verplaatsen...',
        pleaseWait: 'Even wachten...',
        postpone: 'Uitstellen',
        postponeTitle: 'Sla het id van het item op en stel de samenvoeging uit',
        processPostponed: 'Voer de uitgestelde samenvoeging uit',
        requestDeletion: 'Verzoek verwijdering voor extra items op RfD',
        requestingDeletion: 'Verwijdering verzoeken...',
        requestingStreamDeletion: 'Streamverwijdering verzoeken...',
        sendingToRfd: 'Versturen naar RfD...',
        streamDelete: 'Verzoek $1StreamDeletion$2 voor dit item (experimenteel)',
        unwatchOption: 'Verwijder samengevoegde items van volglijst (als deze erop staan)',
        unwatching: 'Verwijderen van volglijst...'
      },
      'pl': {
        close: 'Zamknij',
        closeDialog: 'Zamknij okno bez łączenia elementów',
        confilictMessage: 'A conflict detected on ',
        confilictWithMessage: 'z',
        deleteOption: 'Spróbuj automatycznie usunąć puste elementy po zakończeniu łączenia (tylko dla administratorów)',
        deleting: 'Usuwanie...',
        deletingItem: 'Usuwanie elementu...',
        itemDeleterAccessError: 'Nie jesteś administratorem',
        itemIdInvalid: 'The item\'s id is not defined',
        loadingMergeDestination: 'Ładowanie łączonego elementu...',
        lowestQid: 'Zawsze łącz z elementem o niższym ID',
        merge: 'Połącz',
        mergePendingNotification: 'Merge.js has been started.<br/>Now you can focus your browser on the other item.',
        mergeProcess: 'Rozpocznij proces łączenia',
        mergeThisItem: 'Połącz ten element',
        mergeWithInput: 'Połącz z elementem:',
        mergeWithProgress: 'Połącz z...',
        mergeWizard: 'Merge Wizard',
        mergingClaim: 'Merging claims...',
        movingClaim: 'Moving claims...',
        movingSitelink: 'Przenoszenie linków interwiki...',
        pleaseWait: 'Czekaj...',
        postpone: 'Odłóż',
        postponeTitle: 'Store this item\'s id and postpone the merge',
        processPostponed: 'process the postponed merge',
        requestDeletion: 'Zgłoś puste elementy do usunięcia',
        requestingDeletion: 'Zgłaszanie do usunięcia...',
        requestingStreamDeletion: 'Requesting Stream Deletion...',
        sendingToRfd: 'Wysyłanie zgłoszenia do usunięcia...',
        streamDelete: 'Request $1StreamDeletion$2 for this item (experimental)',
        unwatchOption: 'Usuń łączone elementy ze swojej listy obserwowanych (jeśli na niej były)',
        unwatching: 'Usuwanie z listy obserwowanych...'
      },
      'sk': {
        close: 'Zatvoriť',
        closeDialog: 'Zatvoriť toto okno bez spojenia položiek',
        confilictMessage: 'Detekovaný konflikt v',
        confilictWithMessage: 's',
        deleteOption: 'Pokúsiť sa automaticky zmazať extra položky po spojení (len správcovia)',
        deleting: 'Mažem...',
        deletingItem: 'Mažem položku...',
        itemDeleterAccessError: 'Nie ste správca',
        itemIdInvalid: 'Nie je zadané id položky',
        loadingMergeDestination : 'Načítam výsledok spojenia...' ,
        lowestQid: 'Vždy spojiť do položky s nižším číslom',
        merge: 'Spojiť',
        mergePendingNotification: 'Skript Merge.js bol aktivovaný.<br/>Teraz môžete vo vašom prehliadači prejsť na inú položku.',
        mergeProcess: 'Vykonať teraz spojenie',
        mergeThisItem: 'Spojiť položku',
        mergeWithInput: 'Spojiť s:',
        mergeWithProgress: 'Spojiť s...',
        mergeWizard: 'Nástroj na spájanie',
        mergingClaim: 'Spájam tvrdenie...',
        movingClaim: 'Presúvam tvrdenie...',
        movingSitelink: 'Presúvam odkazy...',
        pleaseWait: 'Prosím čakajte...',
        postpone: 'Odložiť',
        postponeTitle: 'Uložiť id položky a odložiť spojenie',
        processPostponed: 'vykonať odložené spojenie',
        requestDeletion: 'Požiadať o zmazanie extra položiek na RfD',
        requestingDeletion: 'Žiadam o zmazanie...',
        requestingStreamDeletion: 'Žiadam o zmazanie (StreamDelete)...',
        sendingToRfd: 'Posielam na RfD...',
        streamDelete: 'Požiadať o $1StreamDelete$2 (experimentálne)',
        unwatchOption: 'Odstrániť spájané položky zo sledovaných stránok (ak sú sledované)',
        unwatching: 'Odstraňujem zo sledovaných stránok...',
    },
      'zh-hans': {
        close: '关闭',
        closeDialog: '关闭窗口但不合并数据项',
        confilictMessage: '存在跨语言冲突:',
        confilictWithMessage: '和',
        deleteOption: '尝试直接删除数据项',
        deleting: '删除中……',
        deletingItem: '数据项正在删除',
        itemDeleterAccessError: '您不是管理员',
        itemIdInvalid: '此数据项不存在',
        loadingMergeDestination: '加载目标项……',
        lowestQid: '并入编号较小的项',
        merge: '合并',
        mergePendingNotification: 'Merge.js已经运行,请前往其他需要合并的项。',
        mergeProcess: '开始合并',
        mergeThisItem: '合并此项',
        mergeWithInput: '要和此项合并的数据项:',
        mergeWithProgress: '合并',
        mergeWizard: '合并数据项',
        mergingClaim: '声明合并中……',
        movingClaim: '声明移动中……',
        movingSitelink: '站点链接移动中……',
        pleaseWait: '请稍候……',
        postpone: '和其他项合并',
        postponeTitle: '储存此项编号以和其他项合并',
        processPostponed: '和已储存项合并',
        requestDeletion: '提请删除重复项',
        requestingDeletion: '提请删除中……',
        requestingStreamDeletion: '提请StreamDeletion中……',
        sendingToRfd: '提请删除中……',
        streamDelete: '(试验中)提请$1StreamDeletion$2',
        unwatchOption: '若可能,从监视列表移除重复项',
        unwatching: '正在从监视列表移除重复项……'
      }
    }, languageNameParts = mw.config.get('wgUserLanguage').split('-'), lang;

    translations.no = translations.nb;
    if (languageNameParts[1] === 'hans' ||
        languageNameParts[1] === 'cn' ||
        languageNameParts[1] === 'sg' ||
        languageNameParts[1] === 'my') {
      lang = 'zh-hans';
    } else if (languageNameParts[1] === 'hant' ||
               languageNameParts[1] === 'hk' ||
               languageNameParts[1] === 'tw' ||
               languageNameParts[1] === 'mo') {
      lang = 'zh-hant';
    } else if (translations[languageNameParts[0]]) {
      lang = languageNameParts[0];
    } else {
      lang = 'en';
    }
    // return to fill messages, it is an object which is filled with local and en messages as fallback
    return $.extend(true, translations.en, translations[lang]);
  }());

  /**
   * Display progress on form dialog
   */
  function displayProgress(message) {
    if ($('#merge-progress-message').length !== 0) {
      $('#merge-progress-message').text(message);
      return;
    }
    $('#merge-form > *').hide();
    $('#merge-form ~ .ui-dialog-buttonpane').hide(); // hide buttons
    $('<div />').css({
      'text-align': 'center',
      'margin': '3em 0',
      'font-size': '120%'
    }).append(
      $('<span />', {
        id: 'merge-progress-message',
        text: message
      }),
      '<br/><br/>',
      $('<progress />', {
        id: 'merge-progress'
      }).css({
        'display': 'block',
        'margin': '1em auto 0',
        'width': '50%'
      })
    ).appendTo('#merge-form');
  }

  /**
   * Display error on form dialog
   */
  function displayError(error, hideReportLink) {
    $('#merge-form > *').hide();
    $('#merge-form ~ .ui-dialog-buttonpane').hide(); // hide buttons
    var reportLink = '<p>Please report above error <a href="//www.wikidata.org/w/index.php?title=MediaWiki_talk:Gadget-Merge.js&action=edit&section=new">here</a> with source and destination of merge.</p>';
    if (hideReportLink === true) { reportLink = ''; }
    $('#merge-form').append($('<div />', {
      'style': 'color: #990000; margin-top: 0.4em;',
      'html': '<p>Error while "' + $('#merge-progress-message').text() + '": ' + error + '</p>' + reportLink
    }));
  }

  /**
   * Check if the user is an admin, and thus can delete items
   */
  function canDelete() {
    return $.inArray('sysop', mw.config.get('wgUserGroups')) !== -1;
  }

  /**
   * Logger function
   */
  function log(tag, m) {
    // console.log(tag, m);
    return;
  }

  /**
   * MediaWiki post request 
   */
  function post(data) {
    log('#post start:', data);
    return new mw.Api().post(data).always(log);
  }

  /**
   * Retrieve items by id
   */
  function getItems(ids, callback) {
    post({
      action: 'wbgetentities',
      ids: ids.join('|'),
      format: 'json'
    }).done(function (data) {
      callback($.map(data.entities, function (x) { return x; }));
    });
  }

  /**
   * Set a Storage to postpone merge and deletion
   */
  function mergePending(id) {
    $.jStorage.set('merge-pending-id', id);
    mw.notify($.parseHTML(messages.mergePendingNotification));
  }

  /**
   * ...and reset this Storage
   */
  function removePending() {
    $.jStorage.deleteKey('merge-pending-id');
  }

  /**
   * Check if items can be merged
   */
  function detectConflicts(items) {
    var all = {},
      conflicts = {};
    $.each(items, function (i) {
      if (items[i].sitelinks !== undefined) {
        $.each(items[i].sitelinks, function (dbName) {
          if (all[dbName] !== undefined && $.compareObject(all[dbName].sitelinks[dbName], items[i].sitelinks[dbName]) === false) {
            if (conflicts[dbName] === undefined) {
              conflicts[dbName] = [all[dbName]];
            }
            conflicts[dbName].push(items[i]);
          }
          all[dbName] = items[i];
        });
      }
    });
    return conflicts;
  }

  /**
   * Sort items by their Q## id. Useful for detecting eligible item to merged into.
   */
  function sortItemsId(items) {
    return $.map($.map(items, function (item) {
      return {
        item: item,
        id: parseInt(item.id.replace(/^Q/i, ''), 10)
      };
    }).sort(function (x, y) { return x.id - y.id; }), function (item) {
      return item.item;
    });
  }

  /**
   * Edit an item
   */
  function editItem(id, data, summary, callback) {
    if (id === undefined) {
      displayError(messages.itemIdInvalid);
      return;
    }
    data.id = undefined;
    post({
      action: 'wbeditentity',
      id: id,
      data: JSON.stringify(data),
      token: mw.user.tokens.get('editToken'),
      summary: summary
    }).done(callback).fail(function (message, data) {
      displayError(message + ', ' + data.error.info);
    });
  }

  /**
   * Delete an item
   */
  function deleteItem(id, reason, callback) {
    if (id === undefined) {
      displayError(messages.itemIdInvalid);
      return;
    }
    if (canDelete() === false) {
      displayError(messages.itemDeleterAccessError);
      return;
    }
    post({
      action: 'delete',
      title: id,
      reason: reason,
      token: mw.user.tokens.get('editToken')
    }).done(callback);
  }

  /**
   * Clone just needed things
   */
  function cloneCleanItem(item) {
    return {
      id: item.id,
      aliases: $.extend(true, {}, item.aliases),
      sitelinks: $.extend(true, {}, item.sitelinks),
      labels: $.extend(true, {}, item.labels),
      descriptions: $.extend(true, {}, item.descriptions)
    };
  }

  /**
   * Check equality of claims
   */
  function areEqualsClaims(a, b) {
    if (a.mainsnak === undefined || b.mainsnak === undefined) {
      return true;
    }

    return $.compareObject(a.mainsnak.datavalue, b.mainsnak.datavalue);
  }

  /**
   * Check equality of references
   */
  function areEqualsReferences(a, b) {
    if (a.snaks === undefined && b.snaks === undefined) {
      return false; // is really possible?
    }

    return $.compareObject(a.snaks, b.snaks);
  }

  /**
   * Check equality of qualifiers
   */
  function areEqualsQualifiers(a, b) {
    return $.compareObject(a, b);
  }

  /**
   * Abstraction to run actions serially.
   * @param callback Will be fired when all actions done
   */
  function ActionsQueue(callback) {
    var index = 0,
      actions = [];
    this.add = function (action) {
      actions.push(action);
    };
    this.start = function () {
      this.step();
    };
    this.step = function () {
      if (actions.length === index) {
        callback();
      } else {
        index = index + 1;
        actions[index - 1](); // or index++ can be used instead these two lines
      }
    };
  }
  // Test:
  // var actions = new ActionsQueue(function () { console.log('finished'); });
  // actions.add(function () { setTimeout(actions.step, 1000); });
  // actions.add(function () { setTimeout(actions.step, 1000); });
  // actions.add(function () { actions.step(); });
  // actions.start();

  /**
   * <progress /> handler
   */
  function ProgressHandler(actions, progress) {
    var max = 0, value = 0;

    this.add = function (x) {
      actions.add(x);
      max = max + 1;
    };
    this.start = function () {
      progress.attr('max', max);
      actions.start();
    };
    this.step = function () {
      value = value + 1;
      progress.attr('value', value);
      actions.step();
    };
  }
  // var p = $('<progress />'), actions = new ProgressHandler(new ActionsQueue(function () { console.log('finished'); }), p);
  // p.appendTo('h1');
  // actions.add(function () { setTimeout(actions.step, 1000); });
  // actions.add(function () { setTimeout(actions.step, 1000); });
  // actions.start();

  /**
   * Set reference for claim
   */
  function addReferenceToClaim(claim, reference, callback, mergeSummary) {
    post({
      action: 'wbsetreference',
      format: 'json',
      statement: claim.id,
      snaks: JSON.stringify(reference.snaks),
      summary: mergeSummary,
      token: mw.user.tokens.get('editToken')
    }).done(callback);
  }

  /**
   * Override a claim
   */
  function setClaim(claim, callback, mergeSummary) {
    post({
      action: 'wbsetclaim',
      format: 'json',
      claim: JSON.stringify(claim),
      summary: mergeSummary,
      token: mw.user.tokens.get('editToken')
    }).done(callback);
  }

  /**
   * Add a claim
   */
  function addClaim(to, claim, callback, summary) {
    // if snaktype is "novalue", seems there is no way to move the claim so give up for now
    if (claim.mainsnak.snaktype === "novalue") {
      callback();
      return;
    }
    post({
      action: 'wbcreateclaim',
      entity: to.id,
      summary: summary,
      property: claim.mainsnak.property,
      snaktype: claim.mainsnak.snaktype,
      value: JSON.stringify(claim.mainsnak.datavalue.value),
      token: mw.user.tokens.get('editToken')
    }).done(function (data) {
      var actions = new ActionsQueue(callback);
      if (claim.qualifiers !== undefined || claim.rank !== data.claim.rank) {
        actions.add(function () {
          var newClaim = $.extend(true, {}, data.claim);
          newClaim.qualifiers = claim.qualifiers;
          newClaim.rank = claim.rank;
          setClaim(newClaim, actions.step, summary);
        });
      }
      if (claim.references !== undefined) {
        $.each(claim.references, function (i) {
          actions.add(function () {
            addReferenceToClaim(data.claim, claim.references[i], actions.step, summary);
          });
        });
      }
      actions.start();
    });
  }

  /**
   * Claim and references moving logic
   */
  function moveClaims(from, to, actions, mergeSummary) {
    var claimsToBeAdd = [],
      claimsToBeMerged = [],
      claims = from.claims;
    if (claims !== undefined) {
      $.each(claims, function (name) {
        $.each(from.claims[name], function (i) {
          var claim = from.claims[name][i],
            available = false;
          if (to.claims !== undefined && to.claims[name] !== undefined) {
            $.each(to.claims[name], function (j) {
              if (areEqualsClaims(claim, to.claims[name][j])) {
                claimsToBeMerged.push({
                  to: to.claims[name][j],
                  from: claim
                });
                available = true;
              }
            });
          }
          if (!available) {
            claimsToBeAdd.push(claim);
          }
        });
      });
    }
    log('Claims to be added: ', claimsToBeAdd);
    $.each(claimsToBeAdd, function (i) {
      actions.add(function () {
        displayProgress(messages.movingClaim);
        addClaim(to, claimsToBeAdd[i], actions.step, 'Added by [[MediaWiki:Gadget-Merge.js]], from [[' + from.id.toUpperCase() + ']]' + mergeSummary);
      });
    });
    log('Claims to be merged: ', claimsToBeMerged);
    $.each(claimsToBeMerged, function (i) {
      var mergeCase = claimsToBeMerged[i],
        qualifiersCount = 0,
        newTo = $.extend(true, {}, claimsToBeMerged[i].to);
      // Merge qualifiers logic
      if (mergeCase.from.qualifiers !== undefined) {
        $.each(mergeCase.from.qualifiers, function (i) {
          $.each(mergeCase.from.qualifiers[i], function (j) {
            var available = false,
              qualifier = mergeCase.from.qualifiers[i][j];
            if (mergeCase.to.qualifiers !== undefined && mergeCase.to.qualifiers[i] !== undefined) {
              $.each(mergeCase.to.qualifiers[i], function (k) {
                if (areEqualsQualifiers(qualifier, mergeCase.to.qualifiers[i][k])) {
                  available = true;
                }
              });
            }
            if (!available) {
              qualifiersCount = qualifiersCount + 1;
              if (newTo.qualifiers === undefined) {
                newTo.qualifiers = {};
              }
              if (newTo.qualifiers[i] === undefined) {
                newTo.qualifiers[i] = [];
              }
              newTo.qualifiers[i].push(qualifier);
            }
          });
        });
        if (qualifiersCount !== 0) {
          actions.add(function () {
            displayProgress(messages.mergingClaim);
            setClaim(newTo, actions.step, mergeSummary);
          });
        }
      }
      // Merge references logic
      if (mergeCase.from.references !== undefined) {
        $.each(mergeCase.from.references, function (j) {
          var reference = mergeCase.from.references[j],
            available = false;
          if (claimsToBeMerged[i].to.references !== undefined) {
            $.each(mergeCase.to.references, function (k) {
              var toReference = mergeCase.to.references[k];
              if (areEqualsReferences(reference, toReference)) {
                available = true;
              }
            });
          }
          if (!available) {
            actions.add(function () {
              displayProgress(messages.mergingClaim);
              addReferenceToClaim(claimsToBeMerged[i].to, reference, actions.step, 'Added by [[MediaWiki:Gadget-Merge.js]], from [[' + from.id.toUpperCase() + ']]' + mergeSummary);
            });
          }
        });
      }
    });
  }

  /**
   * Moving logic
   */
  function moveItemContent(from, to, actions, mergeSummary) {
    var newFrom = cloneCleanItem(from), // clone
      newTo = cloneCleanItem(to);

    newTo.sitelinks = {}; // clean available, it could make problem if there is a invalid sitelinks available on the page
    $.each(newFrom.sitelinks, function (x) {
      newTo.sitelinks[x] = $.extend(true, {}, newFrom.sitelinks[x]);
      newFrom.sitelinks[x].title = '';
    });

    $.each(newFrom.aliases, function (x) {
      if (newTo.aliases[x] === undefined) {
        newTo.aliases[x] = [];
      }
      $.each(newFrom.aliases[x], function (y) {
        newTo.aliases[x].push(newFrom.aliases[x][y]);
      });
    });

    $.each(newFrom.labels, function (x) {
      newTo.labels[x] = $.extend(true, {}, newFrom.labels[x]);
      newFrom.labels[x].value = '';
    });

    $.each(newFrom.descriptions, function (x) {
      newTo.descriptions[x] = $.extend(true, {}, newFrom.descriptions[x]);
      newFrom.descriptions[x].value = '';
    });

    actions.add(function () {
      displayProgress(messages.movingSitelink);
      editItem(from.id, newFrom, 'Removed by [[MediaWiki:Gadget-Merge.js|merge.js]], moving to [[' + to.id.toUpperCase() + ']]' + mergeSummary, actions.step);
    });
    actions.add(function () {
      editItem(to.id, newTo, 'Added by [[MediaWiki:Gadget-Merge.js|merge.js]], moving from [[' + from.id.toUpperCase() + ']]' + mergeSummary, actions.step);
    });
    moveClaims(from, to, actions, mergeSummary); // Original from and to objects, not new cleaned ones
  }

  // Copy edited [[MediaWiki:Gadget-RequestDeletion.js]]
  function requestDeletion(entity, success, reason, triesCount) {
    var MAXRETRY = 10;
    displayProgress(messages.requestingDeletion);
    post({
      'format': 'json',
      'action': 'edit',
      'title': 'Wikidata:Requests for deletions',
      'watchlist': 'nochange',
      'section': 'new',
      'sectiontitle': '[[' + entity + ']]',
      'summary': '/* ' + entity + ' */ requested deletion ([[MediaWiki:Gadget-Merge.js|merge.js]])',
      'text': '{{rfd links|' + entity + '|' + reason + '}}

' + reason + ' ~~' + '~~\n',
      'token': mw.user.tokens.get('editToken')
    }).done(function (data) {
      if (data.error && data.error.info) { // may an edit conflict happened? retry ten times with 3 second interval
        if (triesCount === MAXRETRY) {
          displayError(data.error.info, true);
          return;
        }
        if (triesCount === undefined) {
          triesCount = 0;
        }
        triesCount = triesCount + 1;
        displayProgress(messages.requestingDeletion + ' ' + triesCount + ' / ' + MAXRETRY);
        setTimeout(function () { requestDeletion(entity, success, reason, triesCount); }, 3000);
      } else {
        success();
      }
    }).fail(function (data) {
      displayError(data);
    });
  }

  function requestStreamDeletion(entity, success, mergedTo) {
    post({
      'action': 'edit',
      'appendtext': '\n{{/row|' + entity.replace(/^Q/i, '') + '|to=' + mergedTo.replace(/^Q/i, '') + '}}',
      'title': 'User:Ricordisamoa/StreamDelete',
      'watchlist': 'nochange',
      'summary': '[[' + entity + ']]: requested StreamDeletion ([[MediaWiki:Gadget-Merge.js|merge.js]])',
      'token': mw.user.tokens.get('editToken')
    }).done(function (data) {
      if (data.error && data.error.info) {
        displayError(data.error.info);
      } else {
        success();
      }
    }).fail(function (data) {
      displayError(data);
    });
  }

  /**
   * Remove a page from watchlist
   */
  function unwatch(page, callback) {
    post({
      action: 'watch',
      title: page,
      unwatch: '',
      token: mw.user.tokens.get('watchToken')
    }).done(callback);
  }

  /**
   * Move a batch of items
   */
  function batchMover(items, mergeSummary) {
    displayProgress(messages.pleaseWait);

    var actions = new ProgressHandler(new ActionsQueue(function () {
      displayProgress(messages.loadingMergeDestination);
      window.location = mw.util.getUrl(items.to.id) + '?action=purge';
    }), $('#merge-progress'));

    $.each(items.from, function (i) {
      var x = items.from[i];
      moveItemContent(x, items.to, actions, mergeSummary);

      if ($('#merge-unwatch').is(':checked')) {
        actions.add(function () {
          displayProgress(messages.unwatching);
          unwatch(x.id, actions.step);
        });
      }

      if (canDelete() && $('#merge-delete').is(':checked')) {
        actions.add(function () {
          displayProgress(messages.deleting);
          displayProgress(messages.deletingItem); // FIXME: Why?
          deleteItem(
            x.id,
            'Merged with [[' + items.to.id.toUpperCase() + ']] ([[MediaWiki:Gadget-Merge.js|merge.js]])' + mergeSummary,
            actions.step
          );
        });
      } else if ($('#merge-send-to-rfd').is(':checked')) {
        actions.add(function () {
          displayProgress(messages.sendingToRfd);
          requestDeletion(x.id.toUpperCase(), actions.step, '[[MediaWiki:Gadget-Merge.js|Merged]] with [[' + items.to.id.toUpperCase() + ']]' + mergeSummary);
        });
      } else if ($('#merge-streamdelete').is(':checked')) {
        actions.add(function () {
          displayProgress(messages.requestingStreamDeletion);
          requestStreamDeletion(x.id, actions.step, items.to.id);
        });
      }
    });
    actions.start();
  }

  /**
   * Merge button action
   */
  function merge() {
    var itemsNames = [$('#merge-items').val(), itemId.toUpperCase()],
      isValid = true,
      mergeSummary = $('#merge-summary').val();
    if (/^\w/.test(mergeSummary)) {
      mergeSummary = ' ' + mergeSummary;
    }
    $.each(itemsNames, function (i) {
      if (!/^Q\d*$/i.test(itemsNames[i])) {
        isValid = false;
      }
    });
    if (isValid === false) {
      $('#merge-input-validation-message').text(' Currently only "Qid" is a valid input');
      return;
    }
    displayProgress('');
    getItems(itemsNames, function (items) {
      // duplicate item if just an item is returned
      // if item was being merged to itself this could conflict error that also useful for debugging conflict detector
      if (items.length === 1) {
        items = items.concat(items);
      }

      var conflicts = detectConflicts(items),
        message;
      if ($.map(conflicts, function (x) { return x; }).length === 0) {
        if ($('#merge-always-lowest-id').is(':checked')) {
          items = sortItemsId(items); // sort by Qid _only_if_specified_
        }
        batchMover({
          from: items.slice(1),
          to: items[0]
        }, mergeSummary);
      } else {
        message = $.map(conflicts, function (x, i) {
          return '<br />' + messages.confilictMessage + i + ':' + $.map(x, function (y, j) {
            return ' [[' + x[j].id.toUpperCase() + ']] ' + messages.confilictWithMessage +
              ' [[' + i + ':' + y.sitelinks[i].title + ']]';
          }).join(',');
        }).join('').replace(/\[\[([^\]\:]*?)\:([^\]]*?)\]\]/g, function (x, y, z) {
          return '<a href="' + wikibase.getSite(y).getUrlTo(z) + '">' + y + ':' + z + '</a>';
        });
        displayError(message, true);
      }
    });
  }

  /**
   * Create checkbox html
   */
  function createCheckbox(id, text) {
    return $('<label />', {
      'for': id
    }).css('display', 'block').append($('<input />', {
      'id': id,
      'name': id,
      'type': 'checkbox',
      'checked': $.jStorage.get(id) === true ? 'checked' : undefined
    }), text);
  }

  /**
   * Save options in storage
   */
  function saveOptions() {
    $('#merge-form input:checkbox').each(function (i, x) {
      $.jStorage.set(x.id, x.checked);
    });
  }

  /**
   * Dialog creator and launcher
   */
  function launchDialog(id) {
    if (typeof id !== 'string') {
      id = '';
    }
    var dialog = {
      width: 500,
      autoOpen: false,
      title: messages.mergeWizard,
      modal: true,
      buttons: [{
        text: messages.close,
        title: messages.closeDialog,
        specialButton: 'cancel',
        click: function () {
          saveOptions();
          removePending();
          $(this).dialog('close');
          $(this).remove();
        }
      }, id === '' ? {
        text: messages.postpone,
        title: messages.postponeTitle,
        click: function () {
          saveOptions();
          mergePending(itemId.toUpperCase());
          $(this).dialog('close');
          $(this).remove();
        }
      } : {
        style: 'display:none'
      }, {
        text: messages.merge,
        title: messages.mergeProcess,
        specialButton: 'proceed',
        click: function () {
          saveOptions();
          removePending();
          merge();
        }
      }]
    };
    $('<div />', {
      'id': 'merge-form',
      'style': 'position: relative;'
    }).append(
      $('<div />', {
        'style': 'margin-top: 0.4em;',
        'html': messages.mergeWithInput
      }),
      $('<input />', {
        'id': 'merge-items',
        'style': 'padding: 1px; vertical-align: baseline;'
      }).val(id),
      $('<label />', {
        'for': id
      }).css('display', 'block').append('merge summary: will be prepended by an auto-generated summary',
        $('<input />', {
          'id': 'merge-summary',
          'style': 'padding: 1px; vertical-align: baseline;'
        })),
      $('<span />', {
        'id': 'merge-input-validation-message'
      }).css('color', 'red'),
      createCheckbox('merge-always-lowest-id', messages.lowestQid),
      createCheckbox('merge-send-to-rfd', messages.requestDeletion),
      createCheckbox(
        'merge-streamdelete',
        messages.streamDelete
          .replace(/\$1([\S\s]*)\$2/, '<u><a href="' + mw.util.getUrl('User:Ricordisamoa/StreamDelete') + '">$1</a></u>')
      ),
      canDelete() ? createCheckbox('merge-delete', messages.deleteOption) : '',
      createCheckbox('merge-unwatch', messages.unwatchOption)
    ).dialog(dialog).dialog('open').parent('.ui-dialog').attr('lang', $(document.documentElement).attr('lang'));
  }

  // Initialization
  if (itemId !== null &&
      mw.config.get('wgNamespaceNumber') === 0 &&
      mw.config.get('wgAction') === 'view') {
    $(window).on('focus storage', function () {
      $('#merge-queue-process').remove();
      if ($.jStorage.get('merge-pending-id') !== null &&
          $.jStorage.get('merge-pending-id') !== '' &&
          $.jStorage.get('merge-pending-id').toLowerCase() !== itemId.toLowerCase()) {
        $('<img>')
          .attr({
            'src': '//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Pictogram_voting_merge.svg/26px-Pictogram_voting_merge.svg.png',
            'alt': 'merge icon'
          })
          .wrap('<a>').parent()
          .attr({
            'href': '#',
            'title': 'process the postponed merge'
          })
          .click(function (event) {
            event.preventDefault();
            launchDialog($.jStorage.get('merge-pending-id'));
          })
          .wrap('<li>').parent()
          .attr('id', 'merge-queue-process')
          .prependTo('#p-views ul');
      }
    });
    $(function () {
      $('#merge-queue-process').remove();
      $('#merge-form').remove();
      $('#ca-merge').remove();
      $(mw.util.addPortletLink('p-cactions', '#', messages.mergeWithProgress, 'ca-merge', messages.mergeThisItem))
        .click(function (event) {
          event.preventDefault();
          launchDialog();
        });
    });
  }

  // Export section
  // currently just for [[MediaWiki:Gadget-EmptyDetect.js]], just launchDialog is exposed
  window.mergeTool = {
    launchDialog: launchDialog
  };
}(jQuery, mediaWiki));