Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.js |
— | — | @@ -1,111 +0,0 @@ |
2 | | -function securepoll_strike_popup(e, action, id) { |
3 | | - var pop = document.getElementById('securepoll-popup'); |
4 | | - |
5 | | - var e = window.event || e; |
6 | | - if(!e) return; |
7 | | - var target = e.target || e.srcElement; |
8 | | - if(!target) return; |
9 | | - |
10 | | - if ( pop.parentNode.tagName.toLowerCase() != 'body' ) { |
11 | | - pop = pop.parentNode.removeChild( pop ); |
12 | | - pop = document.body.appendChild( pop ); |
13 | | - } |
14 | | - |
15 | | - var left = 0; |
16 | | - var top = 0; |
17 | | - var containing = target; |
18 | | - while ( containing ) { |
19 | | - left += containing.offsetLeft; |
20 | | - top += containing.offsetTop; |
21 | | - containing = containing.offsetParent; |
22 | | - } |
23 | | - left += target.offsetWidth - 10; |
24 | | - top += target.offsetHeight - 10; |
25 | | - |
26 | | - // Show the appropriate button |
27 | | - var strikeButton = document.getElementById( 'securepoll-strike-button' ); |
28 | | - var unstrikeButton = document.getElementById( 'securepoll-unstrike-button' ); |
29 | | - if ( action == 'strike' ) { |
30 | | - strikeButton.style.display = 'inline'; |
31 | | - strikeButton.disabled = false; |
32 | | - unstrikeButton.style.display = 'none'; |
33 | | - unstrikeButton.disabled = true; |
34 | | - } else { |
35 | | - unstrikeButton.style.display = 'inline'; |
36 | | - unstrikeButton.disabled = false; |
37 | | - strikeButton.style.display = 'none'; |
38 | | - strikeButton.disabled = true; |
39 | | - } |
40 | | - document.getElementById( 'securepoll-strike-result' ).innerHTML = ''; |
41 | | - |
42 | | - // Set the hidden fields for submission |
43 | | - document.getElementById( 'securepoll-action').value = action; |
44 | | - document.getElementById( 'securepoll-vote-id' ).value = id; |
45 | | - |
46 | | - // Show the popup |
47 | | - pop.style.left = left + 'px'; |
48 | | - pop.style.top = top + 'px'; |
49 | | - pop.style.display = 'block'; |
50 | | - |
51 | | - // Focus on the reason box |
52 | | - var reason = document.getElementById( 'securepoll-strike-reason' ); |
53 | | - reason.focus(); |
54 | | - reason.select(); |
55 | | -} |
56 | | - |
57 | | -function securepoll_strike(action) { |
58 | | - var popup = document.getElementById('securepoll-popup'); |
59 | | - if(action == 'cancel') { |
60 | | - popup.style.display = ''; |
61 | | - return; |
62 | | - } |
63 | | - if ( action == 'submit' ) { |
64 | | - action = document.getElementById( 'securepoll-action' ).value; |
65 | | - } |
66 | | - var id = document.getElementById( 'securepoll-vote-id' ).value; |
67 | | - var strikeButton = document.getElementById( 'securepoll-strike-button' ); |
68 | | - var unstrikeButton = document.getElementById( 'securepoll-unstrike-button' ); |
69 | | - var spinner = document.getElementById( 'securepoll-strike-spinner' ); |
70 | | - strikeButton.disabled = true; |
71 | | - unstrikeButton.disabled = true; |
72 | | - spinner.style.display = 'block'; |
73 | | - var reason = document.getElementById( 'securepoll-strike-reason' ).value; |
74 | | - |
75 | | - var processResult = function (xhr) { |
76 | | - spinner.style.display = 'none'; |
77 | | - strikeButton.disabled = false; |
78 | | - unstrikeButton.disabled = false; |
79 | | - |
80 | | - if ( xhr.status >= 300 || xhr.status < 200 ) { |
81 | | - document.getElementById( 'securepoll-strike-result' ).innerHTML = xhr.responseText; |
82 | | - return; |
83 | | - } |
84 | | - |
85 | | - // Evaluate JSON result, with brackets to avoid interpretation as a code block |
86 | | - result = eval( '(' + xhr.responseText + ')' ); |
87 | | - if ( result.status == 'good' ) { |
88 | | - popup.style.display = 'none'; |
89 | | - } else { |
90 | | - document.getElementById( 'securepoll-strike-result' ).innerHTML = result.message; |
91 | | - } |
92 | | - |
93 | | - securepoll_modify_document( action, id ); |
94 | | - }; |
95 | | - |
96 | | - sajax_do_call( 'wfSecurePollStrike', [ action, id, reason ], processResult ); |
97 | | -} |
98 | | - |
99 | | -function securepoll_modify_document( action, voteId ) { |
100 | | - var popupButton = document.getElementById( 'securepoll-popup-' + voteId ); |
101 | | - var row = popupButton.parentNode.parentNode; |
102 | | - if ( action == 'strike' ) { |
103 | | - row.className += ' securepoll-struck-vote'; |
104 | | - popupButton.value = securepoll_unstrike_button; |
105 | | - } else { |
106 | | - row.className = row.className.replace( 'securepoll-struck-vote', '' ); |
107 | | - popupButton.value = securepoll_strike_button; |
108 | | - } |
109 | | - popupButton.onclick = function (event) { |
110 | | - securepoll_strike_popup( event, action == 'strike' ? 'unstrike' : 'strike', voteId ); |
111 | | - } |
112 | | -} |
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll_body.php |
— | — | @@ -1,86 +0,0 @@ |
2 | | -<?php |
3 | | -if ( !defined( 'MEDIAWIKI' ) ) { |
4 | | - die( "Not a valid entry point\n" ); |
5 | | -} |
6 | | - |
7 | | -class SecurePollPage extends UnlistedSpecialPage { |
8 | | - static $pages = array( |
9 | | - 'details' => 'SecurePoll_DetailsPage', |
10 | | - 'dump' => 'SecurePoll_DumpPage', |
11 | | - 'entry' => 'SecurePoll_EntryPage', |
12 | | - 'list' => 'SecurePoll_ListPage', |
13 | | - 'login' => 'SecurePoll_LoginPage', |
14 | | - 'msgdump' => 'SecurePoll_MessageDumpPage', |
15 | | - 'tally' => 'SecurePoll_TallyPage', |
16 | | - 'translate' => 'SecurePoll_TranslatePage', |
17 | | - 'vote' => 'SecurePoll_VotePage', |
18 | | - ); |
19 | | - |
20 | | - /** |
21 | | - * Constructor |
22 | | - */ |
23 | | - public function __construct() { |
24 | | - parent::__construct( 'SecurePoll' ); |
25 | | - } |
26 | | - |
27 | | - /** |
28 | | - * Show the special page |
29 | | - * |
30 | | - * @param $paramString Mixed: parameter passed to the page or null |
31 | | - */ |
32 | | - public function execute( $paramString ) { |
33 | | - global $wgOut, $wgRequest, $wgScriptPath; |
34 | | - |
35 | | - wfLoadExtensionMessages( 'SecurePoll' ); |
36 | | - |
37 | | - $this->setHeaders(); |
38 | | - $wgOut->addLink( array( |
39 | | - 'rel' => 'stylesheet', |
40 | | - 'href' => "$wgScriptPath/extensions/SecurePoll/SecurePoll.css", |
41 | | - 'type' => 'text/css' |
42 | | - ) ); |
43 | | - $wgOut->addScriptFile( "$wgScriptPath/extensions/SecurePoll/SecurePoll.js" ); |
44 | | - |
45 | | - $this->request = $wgRequest; |
46 | | - |
47 | | - $paramString = strval( $paramString ); |
48 | | - if ( $paramString === '' ) { |
49 | | - $paramString = 'entry'; |
50 | | - } |
51 | | - $params = explode( '/', $paramString ); |
52 | | - $pageName = array_shift( $params ); |
53 | | - $page = $this->getSubpage( $pageName ); |
54 | | - if ( !$page ) { |
55 | | - $wgOut->addWikiMsg( 'securepoll-invalid-page', $pageName ); |
56 | | - return; |
57 | | - } |
58 | | - |
59 | | - $page->execute( $params ); |
60 | | - } |
61 | | - |
62 | | - function getSubpage( $name ) { |
63 | | - if ( !isset( self::$pages[$name] ) ) { |
64 | | - return false; |
65 | | - } |
66 | | - $className = self::$pages[$name]; |
67 | | - $page = new $className( $this ); |
68 | | - return $page; |
69 | | - } |
70 | | - |
71 | | - function getElection( $id ) { |
72 | | - $db = wfGetDB( DB_MASTER ); |
73 | | - $row = $db->selectRow( 'securepoll_elections', '*', array( 'el_entity' => $id ), __METHOD__ ); |
74 | | - if ( $row ) { |
75 | | - return SecurePoll_Election::newFromRow( $row ); |
76 | | - } else { |
77 | | - return false; |
78 | | - } |
79 | | - } |
80 | | - |
81 | | - function getEditToken() { |
82 | | - if ( !isset( $_SESSION['spToken'] ) ) { |
83 | | - $_SESSION['spToken'] = sha1( mt_rand() . mt_rand() . mt_rand() ); |
84 | | - } |
85 | | - return $_SESSION['spToken']; |
86 | | - } |
87 | | -} |
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.css |
— | — | @@ -1,44 +0,0 @@ |
2 | | -.securepoll-old-vote { |
3 | | - color: #666; |
4 | | -} |
5 | | -.securepoll-struck-vote td { |
6 | | - text-decoration: line-through; |
7 | | -} |
8 | | -.securepoll-popup { |
9 | | - padding: 0.5em 1em 0.5em 1em; |
10 | | - border: outset; |
11 | | - position: absolute; |
12 | | - height: 7em; |
13 | | - width: 38em; |
14 | | - display: none; |
15 | | - background-color: #ffffdd; |
16 | | - overflow: auto; |
17 | | - z-index: 3; |
18 | | -} |
19 | | -.securepoll-confirm-button { |
20 | | - width: 16%; |
21 | | - margin-left: 16%; |
22 | | - margin-right: 16%; |
23 | | -} |
24 | | -#securepoll-strike-spinner { |
25 | | - display: none; |
26 | | - margin-left: auto; |
27 | | - margin-right: auto; |
28 | | - width: 30px; |
29 | | -} |
30 | | -.securepoll-detail-header { |
31 | | - font-weight: bold; |
32 | | - width: 20%; |
33 | | -} |
34 | | -.securepoll-trans-table { |
35 | | - width: 100%; |
36 | | -} |
37 | | -.securepoll-error-box { |
38 | | - font-size: larger; |
39 | | - border: 2px solid; |
40 | | - padding: .5em 1em; |
41 | | - margin-bottom: 2em; |
42 | | - color: #000; |
43 | | - border-color: red; |
44 | | - background-color: #fff2f2; |
45 | | -} |
Index: branches/wmf-deployment/extensions/SecurePoll/resources/SecurePoll.css |
— | — | @@ -0,0 +1,67 @@ |
| 2 | +.securepoll-old-vote { |
| 3 | + color: #666; |
| 4 | +} |
| 5 | +.securepoll-struck-vote td { |
| 6 | + text-decoration: line-through; |
| 7 | +} |
| 8 | +.securepoll-popup { |
| 9 | + padding: 0.5em 1em 0.5em 1em; |
| 10 | + border: outset; |
| 11 | + position: absolute; |
| 12 | + height: 7em; |
| 13 | + width: 38em; |
| 14 | + display: none; |
| 15 | + background-color: #ffffdd; |
| 16 | + overflow: auto; |
| 17 | + z-index: 3; |
| 18 | +} |
| 19 | +.securepoll-confirm-button { |
| 20 | + width: 16%; |
| 21 | + margin-left: 16%; |
| 22 | + margin-right: 16%; |
| 23 | +} |
| 24 | +#securepoll-strike-spinner { |
| 25 | + display: none; |
| 26 | + margin-left: auto; |
| 27 | + margin-right: auto; |
| 28 | + width: 30px; |
| 29 | +} |
| 30 | +.securepoll-detail-header { |
| 31 | + font-weight: bold; |
| 32 | + width: 20%; |
| 33 | +} |
| 34 | +.securepoll-trans-table { |
| 35 | + width: 100%; |
| 36 | +} |
| 37 | +.securepoll-error-box { |
| 38 | + font-size: larger; |
| 39 | + border: 2px solid; |
| 40 | + padding: .5em 1em; |
| 41 | + margin-bottom: 2em; |
| 42 | + color: #000; |
| 43 | + border-color: red; |
| 44 | + background-color: #fff2f2; |
| 45 | +} |
| 46 | +.securepoll-option-preferential { |
| 47 | + margin-bottom: 0.5em; |
| 48 | +} |
| 49 | +.securepoll-results { |
| 50 | + margin: 1em 1em 1em 0; |
| 51 | + background: #f9f9f9; |
| 52 | + border: 1px #aaa solid; |
| 53 | + border-collapse: collapse; |
| 54 | +} |
| 55 | +.securepoll-results th, .securepoll-results td { |
| 56 | + border: 1px #aaa solid; |
| 57 | + padding: 0.4em; |
| 58 | +} |
| 59 | +.securepoll-results th { |
| 60 | + background: #f2f2f2; |
| 61 | + text-align: center; |
| 62 | +} |
| 63 | +.securepoll-results caption { |
| 64 | + font-weight: bold; |
| 65 | +} |
| 66 | +.securepoll-results-row-heading { |
| 67 | + background: #f2f2f2; |
| 68 | +} |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/resources/SecurePoll.css |
___________________________________________________________________ |
Added: svn:mergeinfo |
Added: svn:eol-style |
1 | 69 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/resources/SecurePoll.js |
— | — | @@ -0,0 +1,111 @@ |
| 2 | +function securepoll_strike_popup(e, action, id) { |
| 3 | + var pop = document.getElementById('securepoll-popup'); |
| 4 | + |
| 5 | + var e = window.event || e; |
| 6 | + if(!e) return; |
| 7 | + var target = e.target || e.srcElement; |
| 8 | + if(!target) return; |
| 9 | + |
| 10 | + if ( pop.parentNode.tagName.toLowerCase() != 'body' ) { |
| 11 | + pop = pop.parentNode.removeChild( pop ); |
| 12 | + pop = document.body.appendChild( pop ); |
| 13 | + } |
| 14 | + |
| 15 | + var left = 0; |
| 16 | + var top = 0; |
| 17 | + var containing = target; |
| 18 | + while ( containing ) { |
| 19 | + left += containing.offsetLeft; |
| 20 | + top += containing.offsetTop; |
| 21 | + containing = containing.offsetParent; |
| 22 | + } |
| 23 | + left += target.offsetWidth - 10; |
| 24 | + top += target.offsetHeight - 10; |
| 25 | + |
| 26 | + // Show the appropriate button |
| 27 | + var strikeButton = document.getElementById( 'securepoll-strike-button' ); |
| 28 | + var unstrikeButton = document.getElementById( 'securepoll-unstrike-button' ); |
| 29 | + if ( action == 'strike' ) { |
| 30 | + strikeButton.style.display = 'inline'; |
| 31 | + strikeButton.disabled = false; |
| 32 | + unstrikeButton.style.display = 'none'; |
| 33 | + unstrikeButton.disabled = true; |
| 34 | + } else { |
| 35 | + unstrikeButton.style.display = 'inline'; |
| 36 | + unstrikeButton.disabled = false; |
| 37 | + strikeButton.style.display = 'none'; |
| 38 | + strikeButton.disabled = true; |
| 39 | + } |
| 40 | + document.getElementById( 'securepoll-strike-result' ).innerHTML = ''; |
| 41 | + |
| 42 | + // Set the hidden fields for submission |
| 43 | + document.getElementById( 'securepoll-action').value = action; |
| 44 | + document.getElementById( 'securepoll-vote-id' ).value = id; |
| 45 | + |
| 46 | + // Show the popup |
| 47 | + pop.style.left = left + 'px'; |
| 48 | + pop.style.top = top + 'px'; |
| 49 | + pop.style.display = 'block'; |
| 50 | + |
| 51 | + // Focus on the reason box |
| 52 | + var reason = document.getElementById( 'securepoll-strike-reason' ); |
| 53 | + reason.focus(); |
| 54 | + reason.select(); |
| 55 | +} |
| 56 | + |
| 57 | +function securepoll_strike(action) { |
| 58 | + var popup = document.getElementById('securepoll-popup'); |
| 59 | + if(action == 'cancel') { |
| 60 | + popup.style.display = ''; |
| 61 | + return; |
| 62 | + } |
| 63 | + if ( action == 'submit' ) { |
| 64 | + action = document.getElementById( 'securepoll-action' ).value; |
| 65 | + } |
| 66 | + var id = document.getElementById( 'securepoll-vote-id' ).value; |
| 67 | + var strikeButton = document.getElementById( 'securepoll-strike-button' ); |
| 68 | + var unstrikeButton = document.getElementById( 'securepoll-unstrike-button' ); |
| 69 | + var spinner = document.getElementById( 'securepoll-strike-spinner' ); |
| 70 | + strikeButton.disabled = true; |
| 71 | + unstrikeButton.disabled = true; |
| 72 | + spinner.style.display = 'block'; |
| 73 | + var reason = document.getElementById( 'securepoll-strike-reason' ).value; |
| 74 | + |
| 75 | + var processResult = function (xhr) { |
| 76 | + spinner.style.display = 'none'; |
| 77 | + strikeButton.disabled = false; |
| 78 | + unstrikeButton.disabled = false; |
| 79 | + |
| 80 | + if ( xhr.status >= 300 || xhr.status < 200 ) { |
| 81 | + document.getElementById( 'securepoll-strike-result' ).innerHTML = xhr.responseText; |
| 82 | + return; |
| 83 | + } |
| 84 | + |
| 85 | + // Evaluate JSON result, with brackets to avoid interpretation as a code block |
| 86 | + result = eval( '(' + xhr.responseText + ')' ); |
| 87 | + if ( result.status == 'good' ) { |
| 88 | + popup.style.display = 'none'; |
| 89 | + } else { |
| 90 | + document.getElementById( 'securepoll-strike-result' ).innerHTML = result.message; |
| 91 | + } |
| 92 | + |
| 93 | + securepoll_modify_document( action, id ); |
| 94 | + }; |
| 95 | + |
| 96 | + sajax_do_call( 'wfSecurePollStrike', [ action, id, reason ], processResult ); |
| 97 | +} |
| 98 | + |
| 99 | +function securepoll_modify_document( action, voteId ) { |
| 100 | + var popupButton = document.getElementById( 'securepoll-popup-' + voteId ); |
| 101 | + var row = popupButton.parentNode.parentNode; |
| 102 | + if ( action == 'strike' ) { |
| 103 | + row.className += ' securepoll-struck-vote'; |
| 104 | + popupButton.value = securepoll_unstrike_button; |
| 105 | + } else { |
| 106 | + row.className = row.className.replace( 'securepoll-struck-vote', '' ); |
| 107 | + popupButton.value = securepoll_strike_button; |
| 108 | + } |
| 109 | + popupButton.onclick = function (event) { |
| 110 | + securepoll_strike_popup( event, action == 'strike' ? 'unstrike' : 'strike', voteId ); |
| 111 | + } |
| 112 | +} |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/resources/SecurePoll.js |
___________________________________________________________________ |
Added: svn:mergeinfo |
Added: svn:eol-style |
1 | 113 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/resources/critical-32.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/resources/critical-32.png |
___________________________________________________________________ |
Added: svn:mime-type |
2 | 114 | + image/png |
Added: svn:executable |
3 | 115 | + * |
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.alias.php |
— | — | @@ -68,6 +68,11 @@ |
69 | 69 | 'SecurePoll' => array( 'Affshtemme' ), |
70 | 70 | ); |
71 | 71 | |
| 72 | +/** Luxembourgish (Lëtzebuergesch) */ |
| 73 | +$aliases['lb'] = array( |
| 74 | + 'SecurePoll' => array( 'Sécher Ofstëmmung' ), |
| 75 | +); |
| 76 | + |
72 | 77 | /** Nedersaksisch (Nedersaksisch) */ |
73 | 78 | $aliases['nds-nl'] = array( |
74 | 79 | 'SecurePoll' => array( 'Beveilig_stemmen' ), |
— | — | @@ -83,8 +88,18 @@ |
84 | 89 | 'SecurePoll' => array( 'Sikker avstemning' ), |
85 | 90 | ); |
86 | 91 | |
| 92 | +/** Occitan (Occitan) */ |
| 93 | +$aliases['oc'] = array( |
| 94 | + 'SecurePoll' => array( 'Vòte securizat' ), |
| 95 | +); |
| 96 | + |
87 | 97 | /** Polish (Polski) */ |
88 | 98 | $aliases['pl'] = array( |
89 | 99 | 'SecurePoll' => array( 'Bezpieczne głosowanie' ), |
90 | 100 | ); |
91 | 101 | |
| 102 | +/** Slovak (Slovenčina) */ |
| 103 | +$aliases['sk'] = array( |
| 104 | + 'SecurePoll' => array( 'BezpečnéHlasovanie' ), |
| 105 | +); |
| 106 | + |
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.sql |
— | — | @@ -1,106 +1,218 @@ |
2 | 2 | |
| 3 | +-- Generic entity ID allocation |
3 | 4 | CREATE TABLE /*_*/securepoll_entity ( |
| 5 | + -- ID |
4 | 6 | en_id int not null primary key auto_increment, |
| 7 | + |
| 8 | + -- "election", "question" or "option" |
5 | 9 | en_type varbinary(32) not null |
6 | 10 | ) /*$wgDBTableOptions*/; |
7 | 11 | |
| 12 | + |
| 13 | +-- i18n text associated with an entity |
8 | 14 | CREATE TABLE /*_*/securepoll_msgs ( |
| 15 | + -- securepoll_entity.en_id |
9 | 16 | msg_entity int not null, |
| 17 | + |
| 18 | + -- Language code |
10 | 19 | msg_lang varbinary(32) not null, |
| 20 | + |
| 21 | + -- Message key |
11 | 22 | msg_key varbinary(32) not null, |
| 23 | + |
| 24 | + -- Message text, UTF-8 encoded |
12 | 25 | msg_text mediumtext not null |
13 | 26 | ) /*$wgDBTableOptions*/; |
14 | 27 | CREATE UNIQUE INDEX /*i*/spmsg_entity ON /*_*/securepoll_msgs (msg_entity, msg_lang, msg_key); |
15 | 28 | |
| 29 | + |
| 30 | +-- key/value pairs (properties) associated with an entity |
16 | 31 | CREATE TABLE /*_*/securepoll_properties ( |
| 32 | + -- securepoll_entity.en_id |
17 | 33 | pr_entity int not null, |
| 34 | + |
| 35 | + -- Property key |
18 | 36 | pr_key varbinary(32) not null, |
| 37 | + |
| 38 | + -- Property value |
19 | 39 | pr_value mediumblob not null |
20 | 40 | ) /*$wgDBTableOptions*/; |
21 | 41 | CREATE UNIQUE INDEX /*i*/sppr_entity ON /*_*/securepoll_properties (pr_entity, pr_key); |
22 | 42 | |
| 43 | + |
| 44 | +-- List of elections (or polls, surveys, etc) |
23 | 45 | CREATE TABLE /*_*/securepoll_elections ( |
| 46 | + -- securepoll_entity.en_id |
24 | 47 | el_entity int not null primary key, |
| 48 | + |
| 49 | + -- Election title |
| 50 | + -- Only used for the election list on the entry page |
25 | 51 | el_title varchar(255) not null, |
| 52 | + |
| 53 | + -- Owner user.user_id |
| 54 | + el_owner int not null, |
| 55 | + |
| 56 | + -- Ballot type, see Ballot.php |
26 | 57 | el_ballot varchar(32) not null, |
| 58 | + |
| 59 | + -- Tally type, see Tally.php |
27 | 60 | el_tally varchar(32) not null, |
| 61 | + |
| 62 | + -- Primary (administrative) language |
| 63 | + -- This is the primary source for translations |
28 | 64 | el_primary_lang varbinary(32) not null, |
| 65 | + |
| 66 | + -- Start date, in 14-char MW format |
29 | 67 | el_start_date varbinary(14), |
| 68 | + |
| 69 | + -- End date, in 14-char MW format |
30 | 70 | el_end_date varbinary(14), |
| 71 | + |
| 72 | + -- User authorisation type, see Auth.php |
31 | 73 | el_auth_type varbinary(32) not null |
32 | 74 | ) /*$wgDBTableOptions*/; |
33 | 75 | CREATE UNIQUE INDEX /*i*/spel_title ON /*_*/securepoll_elections (el_title); |
34 | 76 | |
| 77 | + |
| 78 | +-- Questions, see Question.php |
35 | 79 | CREATE TABLE /*_*/securepoll_questions ( |
| 80 | + -- securepoll_entity.en_id |
36 | 81 | qu_entity int not null primary key, |
| 82 | + |
| 83 | + -- securepoll_elections.el_entity |
37 | 84 | qu_election int not null, |
| 85 | + |
| 86 | + -- Index determining the order the questions are shown, if shuffle is off |
38 | 87 | qu_index int not null |
39 | 88 | ) /*$wgDBTableOptions*/; |
40 | 89 | CREATE INDEX /*i*/spqu_election_index ON /*_*/securepoll_questions (qu_election, qu_index, qu_entity); |
41 | 90 | |
| 91 | + |
| 92 | +-- Options for answering a given question, see Option.php |
| 93 | +-- FIXME: needs op_election index for import.php |
42 | 94 | CREATE TABLE /*_*/securepoll_options ( |
| 95 | + -- securepoll_entity.en_id |
43 | 96 | op_entity int not null primary key, |
| 97 | + -- securepoll_elections.el_entity |
44 | 98 | op_election int not null, |
| 99 | + -- securepoll_questions.qu_entity |
45 | 100 | op_question int not null |
46 | 101 | ) /*$wgDBTableOptions*/; |
47 | 102 | CREATE INDEX /*i*/spop_question ON /*_*/securepoll_options (op_question, op_entity); |
48 | 103 | |
| 104 | + |
| 105 | +-- Voter list, independent for each election |
| 106 | +-- See Voter.php |
49 | 107 | CREATE TABLE /*_*/securepoll_voters ( |
| 108 | + -- Primary key |
50 | 109 | voter_id int not null primary key auto_increment, |
| 110 | + -- securepoll_elections.el_id |
51 | 111 | voter_election int not null, |
| 112 | + -- The voter's name, as it appears on the remote site |
52 | 113 | voter_name varchar(255) binary not null, |
| 114 | + -- The auth type that created this voter |
53 | 115 | voter_type varbinary(32) not null, |
| 116 | + -- The voter's domain, should be fully-qualified |
54 | 117 | voter_domain varbinary(255) not null, |
| 118 | + -- A URL uniquely identifying the voter |
55 | 119 | voter_url blob, |
| 120 | + -- serialized properties blob |
56 | 121 | voter_properties blob |
57 | 122 | ) /*$wgDBTableOptions*/; |
58 | 123 | CREATE INDEX /*i*/spvoter_elec_name_domain ON /*_*/securepoll_voters |
59 | 124 | (voter_election, voter_name, voter_domain); |
60 | 125 | |
| 126 | +-- Votes that have been cast |
| 127 | +-- Contains a blob with answers to all questions |
61 | 128 | CREATE TABLE /*_*/securepoll_votes ( |
62 | 129 | vote_id int not null primary key auto_increment, |
| 130 | + -- securepoll_elections.el_id |
63 | 131 | vote_election int not null, |
| 132 | + -- securepoll_voters.voter_id |
64 | 133 | vote_voter int not null, |
65 | 134 | |
66 | 135 | -- Denormalised fields from the user table for efficient sorting |
| 136 | + |
| 137 | + -- securepoll_voters.voter_name |
67 | 138 | vote_voter_name varchar(255) binary not null, |
| 139 | + -- securepoll_voters.voter_domain |
68 | 140 | vote_voter_domain varbinary(32) not null, |
69 | 141 | |
70 | 142 | -- Denormalised field from the strike table |
71 | 143 | -- 1 if struck, 0 if not struck |
72 | 144 | vote_struck tinyint not null, |
73 | 145 | |
| 146 | + -- The voting record, produced and interpreted by the ballot type |
| 147 | + -- May be encrypted |
74 | 148 | vote_record blob not null, |
| 149 | + |
| 150 | + -- The IP address, in hexadecimal form (IP::toHex()) |
75 | 151 | vote_ip varbinary(32) not null, |
| 152 | + |
| 153 | + -- The X-Forwarded-For header |
76 | 154 | vote_xff varbinary(255) not null, |
| 155 | + |
| 156 | + -- The User-Agent header |
77 | 157 | vote_ua varbinary(255) not null, |
| 158 | + |
| 159 | + -- MW-format timestamp when the vote was cast |
78 | 160 | vote_timestamp varbinary(14) not null, |
| 161 | + |
| 162 | + -- 1 if the vote is current, 0 if old |
| 163 | + -- Only one vote with a given voter will have vote_current=1 |
79 | 164 | vote_current tinyint not null, |
| 165 | + |
| 166 | + -- 1 if the CSRF token matched (good), 0 for a potential hack |
80 | 167 | vote_token_match tinyint not null, |
| 168 | + |
| 169 | + -- 1 if the vote is flagged as being made by a potential sockpuppet |
| 170 | + -- Details in securepoll_cookie_match |
81 | 171 | vote_cookie_dup tinyint not null |
82 | 172 | ) /*$wgDBTableOptions*/; |
| 173 | +-- For list subpage, sorted by timestamp |
83 | 174 | CREATE INDEX /*i*/spvote_timestamp ON /*_*/securepoll_votes |
84 | 175 | (vote_election, vote_timestamp); |
| 176 | +-- For list subpage, sorted by name |
85 | 177 | CREATE INDEX /*i*/spvote_voter_name ON /*_*/securepoll_votes |
86 | 178 | (vote_election, vote_voter_name, vote_timestamp); |
| 179 | +-- For list subpage, sorted by domain |
87 | 180 | CREATE INDEX /*i*/spvote_voter_domain ON /*_*/securepoll_votes |
88 | 181 | (vote_election, vote_voter_domain, vote_timestamp); |
| 182 | +-- For list subpage, sorted by IP |
89 | 183 | CREATE INDEX /*i*/spvote_ip ON /*_*/securepoll_votes |
90 | 184 | (vote_election, vote_ip, vote_timestamp); |
91 | 185 | |
| 186 | +-- Log of admin strike actions |
92 | 187 | CREATE TABLE /*_*/securepoll_strike ( |
| 188 | + -- Primary key |
93 | 189 | st_id int not null primary key auto_increment, |
| 190 | + |
| 191 | + -- securepoll_votes.vote_id |
94 | 192 | st_vote int not null, |
| 193 | + |
| 194 | + -- Time at which the action occurred |
95 | 195 | st_timestamp varbinary(14) not null, |
| 196 | + |
| 197 | + -- "strike" or "unstrike" |
96 | 198 | st_action varbinary(32) not null, |
| 199 | + |
| 200 | + -- Explanatory reason |
97 | 201 | st_reason varchar(255) not null, |
| 202 | + |
| 203 | + -- user.user_id who did the action |
98 | 204 | st_user int not null |
99 | 205 | ) /*$wgDBTableOptions*/; |
| 206 | +-- For details subpage (strike log) |
100 | 207 | CREATE INDEX /*i*/spstrike_vote ON /*_*/securepoll_strike |
101 | 208 | (st_vote, st_timestamp); |
102 | 209 | |
| 210 | + |
| 211 | +-- Local voter qualification lists |
| 212 | +-- Currently manually populated, referenced by Auth.php |
103 | 213 | CREATE TABLE /*_*/securepoll_lists ( |
| 214 | + -- List name |
104 | 215 | li_name varbinary(255), |
| 216 | + -- user.user_id |
105 | 217 | li_member int not null |
106 | 218 | ) /*$wgDBTableOptions*/; |
107 | 219 | CREATE INDEX /*i*/splists_name ON /*_*/securepoll_lists |
— | — | @@ -108,11 +220,17 @@ |
109 | 221 | CREATE INDEX /*i*/splists_member ON /*_*/securepoll_lists |
110 | 222 | (li_member, li_name); |
111 | 223 | |
| 224 | +-- Suspicious cookie match logs |
112 | 225 | CREATE TABLE /*_*/securepoll_cookie_match ( |
| 226 | + -- Primary key |
113 | 227 | cm_id int not null primary key auto_increment, |
| 228 | + -- securepoll_elections.el_id |
114 | 229 | cm_election int not null, |
| 230 | + -- securepoll_voters.voter_id |
115 | 231 | cm_voter_1 int not null, |
| 232 | + -- securepoll_voters.voter_id |
116 | 233 | cm_voter_2 int not null, |
| 234 | + -- Timestamp at which the match was logged |
117 | 235 | cm_timestamp varbinary(14) not null |
118 | 236 | ) /*$wgDBTableOptions*/; |
119 | 237 | CREATE INDEX /*i*/spcookie_match_voter_1 ON /*_*/securepoll_cookie_match |
Index: branches/wmf-deployment/extensions/SecurePoll/auth-api.php |
— | — | @@ -37,6 +37,8 @@ |
38 | 38 | echo serialize( Status::newFatal( 'securepoll-api-token-mismatch' ) ); |
39 | 39 | exit; |
40 | 40 | } |
41 | | -$status = Status::newGood( SecurePoll_LocalAuth::getUserParams( $user ) ); |
| 41 | +$context = new SecurePoll_Context; |
| 42 | +$auth = $context->newAuth( 'local' ); |
| 43 | +$status = Status::newGood( $auth->getUserParams( $user ) ); |
42 | 44 | echo serialize( $status ); |
43 | 45 | |
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.i18n.php |
— | — | @@ -57,10 +57,11 @@ |
58 | 58 | 'securepoll-no-decryption-key' => 'No decryption key is configured. |
59 | 59 | Cannot decrypt.', |
60 | 60 | 'securepoll-jump' => 'Go to the voting server', |
61 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
62 | | - Your vote was invalid: $1 |
63 | | - </div>', |
| 61 | + 'securepoll-bad-ballot-submission' => 'Your vote was invalid: $1', |
64 | 62 | 'securepoll-unanswered-questions' => 'You must answer all questions.', |
| 63 | + 'securepoll-invalid-rank' => 'Invalid rank. You must give candidates a rank between 1 and 999.', |
| 64 | + 'securepoll-unranked-options' => 'Some options were not ranked. |
| 65 | +You must give all options a rank between 1 and 999.', |
65 | 66 | |
66 | 67 | # Authorisation related |
67 | 68 | 'securepoll-remote-auth-error' => 'Error fetching your account information from the server.', |
— | — | @@ -75,6 +76,7 @@ |
76 | 77 | 'securepoll-bot' => 'Sorry, accounts with the bot flag are not allowed to vote in this election.', |
77 | 78 | 'securepoll-not-in-group' => 'Only members of the "$1" group can vote in this election.', |
78 | 79 | 'securepoll-not-in-list' => 'Sorry, you are not in the predetermined list of users authorised to vote in this election.', |
| 80 | + 'securepoll-custom-unqualified' => '$1', |
79 | 81 | |
80 | 82 | # List page |
81 | 83 | # Mostly for admins |
— | — | @@ -94,6 +96,7 @@ |
95 | 97 | 'securepoll-strike-reason' => 'Reason:', |
96 | 98 | 'securepoll-strike-cancel' => 'Cancel', |
97 | 99 | 'securepoll-strike-error' => 'Error performing strike/unstrike: $1', |
| 100 | + 'securepoll-strike-token-mismatch' => 'Session data lost', |
98 | 101 | 'securepoll-details-link' => 'Details', |
99 | 102 | |
100 | 103 | # Details page |
— | — | @@ -116,6 +119,8 @@ |
117 | 120 | 'securepoll-dump-not-finished' => 'Encrypted election records are only available after the finish date on $1 at $2', |
118 | 121 | 'securepoll-dump-no-urandom' => 'Cannot open /dev/urandom. |
119 | 122 | To maintain voter privacy, encrypted election records are only publically available when they can be shuffled with a secure random number stream.', |
| 123 | + 'securepoll-urandom-not-supported' => 'This server does not support cryptographic random number generation. |
| 124 | +To maintain voter privacy, encrypted election records are only publically available when they can be shuffled with a secure random number stream.', |
120 | 125 | |
121 | 126 | # Translate page |
122 | 127 | 'securepoll-translate-title' => 'Translate: $1', |
— | — | @@ -147,6 +152,11 @@ |
148 | 153 | 'securepoll-tally-upload-submit' => 'Create tally', |
149 | 154 | 'securepoll-tally-error' => 'Error interpreting vote record, cannot produce a tally.', |
150 | 155 | 'securepoll-no-upload' => 'No file was uploaded, cannot tally results.', |
| 156 | + 'securepoll-dump-corrupt' => 'The dump file is corrupt and cannot be processed.', |
| 157 | + 'securepoll-tally-upload-error' => 'Error tallying dump file: $1', |
| 158 | + 'securepoll-pairwise-victories' => 'Pairwise victory matrix', |
| 159 | + 'securepoll-strength-matrix' => 'Path strength matrix', |
| 160 | + 'securepoll-ranks' => 'Final ranking', |
151 | 161 | ); |
152 | 162 | |
153 | 163 | /** Message documentation (Message documentation) |
— | — | @@ -154,20 +164,27 @@ |
155 | 165 | * @author EugeneZelenko |
156 | 166 | * @author Fryed-peach |
157 | 167 | * @author IAlex |
| 168 | + * @author Kiranmayee |
158 | 169 | * @author Kwj2772 |
| 170 | + * @author Lloffiwr |
159 | 171 | * @author Mormegil |
160 | 172 | * @author Purodha |
161 | 173 | * @author Raymond |
| 174 | + * @author Saper |
162 | 175 | * @author Siebrand |
163 | 176 | */ |
164 | 177 | $messages['qqq'] = array( |
165 | | - 'securepoll-desc' => 'A short description of this extension shown in [[Special:Version]]. |
166 | | -{{doc-important|Do not translate tag names.}} |
167 | | -{{doc-important|Do not translate links.}}', |
| 178 | + 'securepoll-desc' => '{{desc}}', |
168 | 179 | 'securepoll-not-started' => '* $2 is the date of it |
169 | 180 | * $3 is its time.', |
170 | 181 | 'securepoll-return' => '{{Identical|Return to $1}}', |
171 | | - 'securepoll-secret-gpg-error' => "<span style=\"color:red\">'''DO <u>NOT</u> translate LocalSettings.php and \$wgSecurePollShowErrorDetail=true;'''</span>", |
| 182 | + 'securepoll-no-gpg-home' => 'GPG stands for [http://en.wikipedia.org/wiki/GNU_Privacy_Guard GNU Privacy Guard].', |
| 183 | + 'securepoll-secret-gpg-error' => "<span style=\"color:red\">'''DO <u>NOT</u> translate LocalSettings.php and \$wgSecurePollShowErrorDetail=true;'''</span> |
| 184 | + |
| 185 | +GPG stands for [http://en.wikipedia.org/wiki/GNU_Privacy_Guard GNU Privacy Guard].", |
| 186 | + 'securepoll-full-gpg-error' => 'GPG stands for [http://en.wikipedia.org/wiki/GNU_Privacy_Guard GNU Privacy Guard].', |
| 187 | + 'securepoll-gpg-config-error' => 'GPG stands for [http://en.wikipedia.org/wiki/GNU_Privacy_Guard GNU Privacy Guard].', |
| 188 | + 'securepoll-gpg-parse-error' => 'GPG stands for [http://en.wikipedia.org/wiki/GNU_Privacy_Guard GNU Privacy Guard].', |
172 | 189 | 'securepoll-header-timestamp' => '{{Identical|Time}}', |
173 | 190 | 'securepoll-header-voter-name' => '{{Identical|Name}}', |
174 | 191 | 'securepoll-header-ip' => '{{optional}}', |
— | — | @@ -187,15 +204,22 @@ |
188 | 205 | 'securepoll-invalid-vote' => 'The vote ID identifies a specific voting process.', |
189 | 206 | 'securepoll-header-id' => '{{optional}}', |
190 | 207 | 'securepoll-header-url' => '{{optional}}', |
| 208 | + 'securepoll-header-action' => '{{Identical|Action}}', |
191 | 209 | 'securepoll-header-reason' => '{{Identical|Reason}}', |
192 | 210 | 'securepoll-cookie-dup-list' => 'Header of a list on [[Special:SecurePoll/details/1]]. The list shows duplicate voters detected by having a cookie from the first voting.', |
193 | 211 | 'securepoll-dump-not-finished' => '* $1 is the date |
194 | 212 | * $2 is the time', |
195 | | - 'securepoll-dump-no-urandom' => 'Do not translate "/dev/urandom".', |
| 213 | + 'securepoll-dump-no-urandom' => 'Do not translate "/dev/urandom". |
| 214 | + |
| 215 | +Servers running Microsoft Windows will present [[MediaWiki:Securepoll-urandom-not-supported/en|Securepoll-urandom-not-supported]] instead.', |
| 216 | + 'securepoll-urandom-not-supported' => "As to the meaning of ''cryptographic random number'', see [[:wikipedia:Cryptographically secure pseudorandom number generator]] for reference. |
| 217 | + |
| 218 | +The /dev/urandom cryptographic random number generation device is not supported on servers running Microsoft Windows. On other platforms the [[MediaWiki:Securepoll-dump-no-urandom/en|Securepoll-dump-no-urandom]] message is generated if opening of the /dev/urandom device fails.", |
196 | 219 | 'securepoll-translate-title' => '{{Identical|Translate}}', |
197 | 220 | 'securepoll-header-trans-id' => '{{optional}}', |
198 | 221 | 'securepoll-submit-select-lang' => '{{Identical|Translate}}', |
199 | 222 | 'securepoll-header-title' => '{{Identical|Name}}', |
| 223 | + 'securepoll-subpage-vote' => 'వోటు', |
200 | 224 | 'securepoll-subpage-translate' => '{{Identical|Translate}}', |
201 | 225 | ); |
202 | 226 | |
— | — | @@ -248,17 +272,18 @@ |
249 | 273 | 'securepoll-no-decryption-key' => 'لا توجد مفاتيح فك شفرة مهيئة. |
250 | 274 | لا يمكن فك الشفرة.', |
251 | 275 | 'securepoll-jump' => 'اذهب إلى خادم التصويت', |
252 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
253 | | -تصويتك ليس صحيحا: $1 |
254 | | -</div>', |
| 276 | + 'securepoll-bad-ballot-submission' => 'تصويتك ليس صحيحا: $1', |
255 | 277 | 'securepoll-unanswered-questions' => 'يجب أن تجيب على كل الأسئلة.', |
| 278 | + 'securepoll-invalid-rank' => 'رتبة غير مقبولة. يجب أن تعطي المرشحين رتبة بين 1 و 999.', |
| 279 | + 'securepoll-unranked-options' => 'لم يتم اعطاء رتبة لبعض الخيارات. |
| 280 | +يجب أن تعطي كل الخيارات رتبة ما بين 1 و 999.', |
256 | 281 | 'securepoll-remote-auth-error' => 'خطأ عند جلب معلومات حسابك من الخادوم.', |
257 | 282 | 'securepoll-remote-parse-error' => 'خطأ عند تفسير رد التصريح من الخادوم.', |
258 | 283 | 'securepoll-api-invalid-params' => 'محددات غير صحيحة.', |
259 | 284 | 'securepoll-api-no-user' => 'لم يوجد أي مستخدم بالهوية المعطاة.', |
260 | 285 | 'securepoll-api-token-mismatch' => 'نص الأمان لا يطابق، لا يمكن تسجيل الدخول.', |
261 | 286 | 'securepoll-not-logged-in' => 'يجب أن تدخل لتصوت في هذه الانتخابات', |
262 | | - 'securepoll-too-few-edits' => 'عذرا، لا يمكنك التصويت. يجب أن تكون قد قمت ب$1 {{PLURAL:$1|تعديل|تعديل}} على الأقل لتصوت في هذه الانتخابات، أنت قمت ب$2.', |
| 287 | + 'securepoll-too-few-edits' => 'عذرا لا يمكنك التصويت. يجب أن تقوم ب{{PLURAL:$1||تعديل واحد|تعديلين|$1 تعديلات|$1 تعديلًا|$1 تعديل}} على الأقل لتصوت في هذه الانتخابات، بينما قمت ب$2.', |
263 | 288 | 'securepoll-blocked' => 'عذرا، لا تستطيع التصويت في هذه الانتخابات إذا كنت ممنوعا حاليا من التعديل.', |
264 | 289 | 'securepoll-bot' => 'عذرا، الحسابات ذات أعلام البوت غير مسموح لها بالتصويت في هذه الانتخابات.', |
265 | 290 | 'securepoll-not-in-group' => 'فقط المستخدمين من المجموعة "$1" يمكنهم التصويت في هذه الانتخابات.', |
— | — | @@ -276,6 +301,7 @@ |
277 | 302 | 'securepoll-strike-reason' => 'السبب:', |
278 | 303 | 'securepoll-strike-cancel' => 'الغاء', |
279 | 304 | 'securepoll-strike-error' => 'خطأ اثناء القيام بالشطب/الغاء الشطب: $1', |
| 305 | + 'securepoll-strike-token-mismatch' => 'فقدت بيانات الجلسة', |
280 | 306 | 'securepoll-details-link' => 'التفاصيل', |
281 | 307 | 'securepoll-details-title' => 'تفاصيل التصويت: #$1', |
282 | 308 | 'securepoll-invalid-vote' => '"$1" ليس رمز تعريف تصويت صحيح.', |
— | — | @@ -291,6 +317,8 @@ |
292 | 318 | 'securepoll-dump-not-finished' => 'سجلات الانتخابات المشفرة متاحة فقط بعد تاريخ الانتهاء في $1 ب $2', |
293 | 319 | 'securepoll-dump-no-urandom' => 'لا يمكن فتح /dev/urandom. |
294 | 320 | للحفاظ على خصوصية المصوتين، سجلات الانتخابات المشفرة تتاح على الملأ عندما يمكن خلطهم عن طريق سيل ارقام عشوائية آمن.', |
| 321 | + 'securepoll-urandom-not-supported' => 'هذا الخادم لا يدعم توليد أرقام عن طريق الترميز العشوائي. |
| 322 | +للحفاظ على خصوصية الناخبين ، سجلات الانتخابات المشفرة ليست متاحة علانية الا عندما يمكن خلطهم عن طريق دفق رقمي عشوائي آمن .', |
295 | 323 | 'securepoll-translate-title' => 'ترجم: $1', |
296 | 324 | 'securepoll-invalid-language' => 'كود لغة غير صحيح "$1"', |
297 | 325 | 'securepoll-submit-translate' => 'تحديث', |
— | — | @@ -315,8 +343,19 @@ |
316 | 344 | 'securepoll-tally-upload-submit' => 'أنشئ محصلة', |
317 | 345 | 'securepoll-tally-error' => 'خطأ في تفسير سجل التصويت، تعذّر توليد محصلة.', |
318 | 346 | 'securepoll-no-upload' => 'لم يرفع ملف، تعذّر تحصيل النتائج.', |
| 347 | + 'securepoll-dump-corrupt' => 'ملف التفريغ تالف و لا يمكن معالجته.', |
| 348 | + 'securepoll-tally-upload-error' => 'خطأ أثناء فرز ملف التفريغ: $1', |
319 | 349 | ); |
320 | 350 | |
| 351 | +/** Aramaic (ܐܪܡܝܐ) |
| 352 | + * @author Basharh |
| 353 | + */ |
| 354 | +$messages['arc'] = array( |
| 355 | + 'securepoll-strike-reason' => 'ܥܠܬܐ:', |
| 356 | + 'securepoll-strike-cancel' => 'ܒܛܘܠ', |
| 357 | + 'securepoll-header-reason' => 'ܥܠܬܐ', |
| 358 | +); |
| 359 | + |
321 | 360 | /** Belarusian (Taraškievica orthography) (Беларуская (тарашкевіца)) |
322 | 361 | * @author EugeneZelenko |
323 | 362 | * @author Jim-by |
— | — | @@ -366,6 +405,9 @@ |
367 | 406 | 'securepoll-jump' => 'Перайсьці на сэрвэр галасаваньня', |
368 | 407 | 'securepoll-bad-ballot-submission' => 'Ваш голас ня быў залічаны: $1', |
369 | 408 | 'securepoll-unanswered-questions' => 'Вам неабходна адказаць на ўсе пытаньні.', |
| 409 | + 'securepoll-invalid-rank' => 'Няслушны ранг. Вам неабходна даць кандыдатам ранг паміж 1 і 999.', |
| 410 | + 'securepoll-unranked-options' => 'Некаторыя пункты ня маюць рангу. |
| 411 | +Вам неабходна даць усім пунктам ранг паміж 1 і 999.', |
370 | 412 | 'securepoll-remote-auth-error' => 'Памылка атрыманьня інфармацыі пра Ваш рахунак з сэрвэра.', |
371 | 413 | 'securepoll-remote-parse-error' => 'Памылка інтэрпрэтацыі адказу аўтарызацыі з сэрвэра.', |
372 | 414 | 'securepoll-api-invalid-params' => 'Няслушныя парамэтры.', |
— | — | @@ -390,6 +432,7 @@ |
391 | 433 | 'securepoll-strike-reason' => 'Прычына:', |
392 | 434 | 'securepoll-strike-cancel' => 'Адмяніць', |
393 | 435 | 'securepoll-strike-error' => 'Памылка пад час закрэсьліваньня/адкрэсьліваньня: $1', |
| 436 | + 'securepoll-strike-token-mismatch' => 'Зьвесткі сэсіі страчаныя', |
394 | 437 | 'securepoll-details-link' => 'Падрабязнасьці', |
395 | 438 | 'securepoll-details-title' => 'Падрабязнасьці галасаваньня: #$1', |
396 | 439 | 'securepoll-invalid-vote' => '«$1» не зьяўляецца слушным ідэнтыфікатарам голасу', |
— | — | @@ -405,6 +448,8 @@ |
406 | 449 | 'securepoll-dump-not-finished' => 'Зашыфраваныя выбарчыя запісы даступны толькі пасьля $1 у $2.', |
407 | 450 | 'securepoll-dump-no-urandom' => 'Не магчыма адкрыць /dev/urandom. |
408 | 451 | Каб захаваць прыватнасьць галасоў, зашыфраваныя выбарчыя запісы будуць даступныя для грамадзкасьці, толькі калі іх парадак будуць будзе зьменены з дапамогай бясьпечнай крыніцы выпадковых лікаў.', |
| 452 | + 'securepoll-urandom-not-supported' => 'Гэты сэрвэр не падтрымлівае генэрацыю крыптаграфічных выпадковых лікаў. |
| 453 | +У мэтах захаваньня прыватнасьці галасаваўшых, зашыфраваныя запісы выбараў будуць агульнадаступнымі толькі калі яны могуць быць зьмешаныя са струменем выпадковых лікаў.', |
409 | 454 | 'securepoll-translate-title' => 'Пераклад: $1', |
410 | 455 | 'securepoll-invalid-language' => 'Няслушны код мовы «$1»', |
411 | 456 | 'securepoll-submit-translate' => 'Абнавіць', |
— | — | @@ -429,6 +474,8 @@ |
430 | 475 | 'securepoll-tally-upload-submit' => 'Падлічыць', |
431 | 476 | 'securepoll-tally-error' => 'Памылка інтэрпрэтацыі запісу голасу, немагчыма падлічыць.', |
432 | 477 | 'securepoll-no-upload' => 'Файл не загружаны, немагчыма падлічыць.', |
| 478 | + 'securepoll-dump-corrupt' => 'Вывадны файл пашкоджаны і ня можа быць апрацаваны.', |
| 479 | + 'securepoll-tally-upload-error' => 'Памылка цэласнасьці вываднога файла: $1', |
433 | 480 | ); |
434 | 481 | |
435 | 482 | /** Bulgarian (Български) |
— | — | @@ -501,6 +548,9 @@ |
502 | 549 | 'securepoll-jump' => 'Idi na server za glasanje', |
503 | 550 | 'securepoll-bad-ballot-submission' => 'Vaš glas nije valjan: $1', |
504 | 551 | 'securepoll-unanswered-questions' => 'Morate odgovoriti na sva pitanja.', |
| 552 | + 'securepoll-invalid-rank' => 'Nevaljan rang. Morate dati kandidatima rang između 1 i 999.', |
| 553 | + 'securepoll-unranked-options' => 'Neke opcije nisu rangirane. |
| 554 | +Morate dati svim opcijama rang između 1 i 999.', |
505 | 555 | 'securepoll-remote-auth-error' => 'Greška pri preuzimanju podataka o Vašem računu sa servera.', |
506 | 556 | 'securepoll-remote-parse-error' => 'Greška pri interpretaciji autentifikacijskog odgovora sa servera.', |
507 | 557 | 'securepoll-api-invalid-params' => 'Nevaljani parametri.', |
— | — | @@ -525,6 +575,7 @@ |
526 | 576 | 'securepoll-strike-reason' => 'Razlog:', |
527 | 577 | 'securepoll-strike-cancel' => 'Odustani', |
528 | 578 | 'securepoll-strike-error' => 'Greška izvšavanja precrtavanja/uklanjanja: $1', |
| 579 | + 'securepoll-strike-token-mismatch' => 'Izgubljeni podaci sesije', |
529 | 580 | 'securepoll-details-link' => 'Detalji', |
530 | 581 | 'securepoll-details-title' => 'Detalji glasanja: #$1', |
531 | 582 | 'securepoll-invalid-vote' => '"$1" nije valjan glasački ID', |
— | — | @@ -539,6 +590,8 @@ |
540 | 591 | 'securepoll-dump-no-crypt' => 'Ne postoji dešifrirana varijanta ovog izbora, zato što izbor nije konfiguriran za korištenje šifriranja.', |
541 | 592 | 'securepoll-dump-not-finished' => 'Dešifrirani rezultati izbora su vidljivi tek poslije datuma završetka izbora $1 u $2 sati', |
542 | 593 | 'securepoll-dump-no-urandom' => 'Da bi se sačuvala privatnost glasača, dešifrirani rezultati glasanja su dostupni kada bude dostupna mogućnost prenosa slučajnim izborom brojki.', |
| 594 | + 'securepoll-urandom-not-supported' => 'Ovaj server ne podržava generisanje kriptografskih nasumičnih brojeva. |
| 595 | +Da bi se zadržala privatnost glasača, šifrirani podaci o izborima su dostupni javno kada se mogu izmiješati putem sigurnog toka nasumičnih brojeva.', |
543 | 596 | 'securepoll-translate-title' => 'Prevedi: $1', |
544 | 597 | 'securepoll-invalid-language' => 'Pogrešan kod jezika "$1"', |
545 | 598 | 'securepoll-submit-translate' => 'Ažuriranje', |
— | — | @@ -563,9 +616,13 @@ |
564 | 617 | 'securepoll-tally-upload-submit' => 'Napravi prebrojavanje', |
565 | 618 | 'securepoll-tally-error' => 'Greška pri interpretaciji zapisa glasanja, ne može se izvršiti prebrojavanje.', |
566 | 619 | 'securepoll-no-upload' => 'Nijedna datoteka nije postavljena, ne mogu se prebrojati rezultati.', |
| 620 | + 'securepoll-dump-corrupt' => 'Dump datoteka je pokvarena i ne može biti obrađena.', |
| 621 | + 'securepoll-tally-upload-error' => 'Greška pri ažuriranju dump datoteke: $1', |
567 | 622 | ); |
568 | 623 | |
569 | 624 | /** Catalan (Català) |
| 625 | + * @author Cbrown1023 |
| 626 | + * @author Góngora |
570 | 627 | * @author Jordi Roqué |
571 | 628 | * @author SMP |
572 | 629 | * @author Vriullop |
— | — | @@ -599,34 +656,52 @@ |
600 | 657 | El vostre vot no ha estat enregistrat! |
601 | 658 | |
602 | 659 | $1", |
| 660 | + 'securepoll-no-gpg-home' => 'No es pot crear el directori de GPG.', |
| 661 | + 'securepoll-secret-gpg-error' => 'Error en l\'execució de GPG. |
| 662 | +Useu $wgSecurePollShowErrorDetail=true; al LocalSettings.php per a mostrar més detalls.', |
| 663 | + 'securepoll-full-gpg-error' => "Error en l'execució del GPG: |
| 664 | + |
| 665 | +Comanda: $1 |
| 666 | + |
| 667 | +Error: |
| 668 | +<pre>$2</pre>", |
| 669 | + 'securepoll-gpg-config-error' => 'Les claus GPG estan mal configurades.', |
603 | 670 | 'securepoll-gpg-parse-error' => 'Error en la interpretació de la sortida de GPG', |
604 | 671 | 'securepoll-no-decryption-key' => 'No està configurada la clau de desxifrat. |
605 | 672 | No es pot desencriptar.', |
606 | 673 | 'securepoll-jump' => 'Tornar al servidor de votació', |
607 | 674 | 'securepoll-bad-ballot-submission' => 'El vostre vot no és vàlid: $1', |
608 | 675 | 'securepoll-unanswered-questions' => 'Heu de respondre totes les qüestions.', |
| 676 | + 'securepoll-invalid-rank' => "Rang no vàlid. |
| 677 | +Heu d'introduir a cada candidat un valor entre 1 i 999.", |
| 678 | + 'securepoll-unranked-options' => 'Algunes opcions no han estat qualificades. |
| 679 | +Heu de donar a totes les opcions, un rang entre 1 i 999.', |
609 | 680 | 'securepoll-remote-auth-error' => "S'ha produit un eror en recuperar del servidor la informació del vostre compte .", |
610 | 681 | 'securepoll-remote-parse-error' => "S'ha produit un error en la recepció de la resposta d'autorització des del servidor.", |
611 | 682 | 'securepoll-api-invalid-params' => 'Paràmetres invàlids.', |
612 | 683 | 'securepoll-api-no-user' => "No s'ha trobat cap usuari amb aquesta identificació.", |
| 684 | + 'securepoll-api-token-mismatch' => "El token de seguretat no coincideix. No s'ha pogut accedir.", |
613 | 685 | 'securepoll-not-logged-in' => "Heu d'estar connectats en un compte per a votar en aquesta elecció", |
614 | 686 | 'securepoll-too-few-edits' => "Ho sentim, però no podeu votar. |
615 | 687 | Per a votar en aquesta elecció cal haver fet un mínim {{PLURAL:$1|d'una edició|de $1 edicions}}, i n'heu fet $2.", |
616 | 688 | 'securepoll-blocked' => "Ho sentim però no podeu votar en aquesta elecció perquè el vostre compte està blocat a l'edició.", |
617 | | - 'securepoll-bot' => 'Excuses, però els comptes de bot no poden votar en aquesta elecció.', |
| 689 | + 'securepoll-bot' => 'Ho sentim, però els comptes de bot no poden votar en aquestes eleccions.', |
618 | 690 | 'securepoll-not-in-group' => 'Només els membres del grup «$1» poden votar en aquesta elecció.', |
619 | 691 | 'securepoll-not-in-list' => 'Ho sentim, però no esteu en la llista dels usuaris autoritzats a votar en aquesta elecció.', |
620 | 692 | 'securepoll-list-title' => 'Llista de vots: $1', |
621 | 693 | 'securepoll-header-timestamp' => 'Hora', |
622 | 694 | 'securepoll-header-voter-name' => 'Nom', |
623 | 695 | 'securepoll-header-voter-domain' => 'Domini', |
| 696 | + 'securepoll-header-ua' => '<em>Useragent</em>', |
| 697 | + 'securepoll-header-cookie-dup' => 'Duplicat', |
624 | 698 | 'securepoll-header-strike' => 'Anuŀlació', |
625 | 699 | 'securepoll-header-details' => 'Detalls', |
626 | 700 | 'securepoll-strike-button' => 'Anuŀla', |
627 | 701 | 'securepoll-unstrike-button' => "Desfés l'anuŀlació", |
628 | 702 | 'securepoll-strike-reason' => 'Motiu:', |
629 | 703 | 'securepoll-strike-cancel' => 'Canceŀla', |
630 | | - 'securepoll-strike-error' => "Error en anul·lar o en desfer l'anul·lació: $1", |
| 704 | + 'securepoll-strike-error' => "Error en anuŀlar o en desfer l'anuŀlació: $1", |
| 705 | + 'securepoll-strike-token-mismatch' => 'Pèrdua de dades de la sessió', |
631 | 706 | 'securepoll-details-link' => 'Detalls', |
632 | 707 | 'securepoll-details-title' => 'Detalls de vot: #$1', |
633 | 708 | 'securepoll-invalid-vote' => '«$1» no és una ID de vot vàlida', |
— | — | @@ -636,10 +711,14 @@ |
637 | 712 | 'securepoll-header-action' => 'Acció', |
638 | 713 | 'securepoll-header-reason' => 'Motiu', |
639 | 714 | 'securepoll-header-admin' => 'Administrador', |
| 715 | + 'securepoll-cookie-dup-list' => 'Usuaris amb galetes duplicades', |
| 716 | + 'securepoll-dump-title' => 'Abocament: $1', |
640 | 717 | 'securepoll-dump-no-crypt' => 'No existeix cap registre encriptat en aquesta elecció perquè no està configurada per usar encriptació.', |
641 | 718 | 'securepoll-dump-not-finished' => "Els registres encriptats de l'elecció només estaran disponibles després de la seva conclusió, a $1 del $2", |
642 | 719 | 'securepoll-dump-no-urandom' => "No es pot obrir /dev/urandom. |
643 | 720 | Per mantenir la privacitat dels votants, els registres encriptats de l'elecció es fan públics només quan poden ser barrejats amb un generador segur de nombres aleatoris.", |
| 721 | + 'securepoll-urandom-not-supported' => "Aquest servidor no suporta la generació criptogràfica de nombres aleatoris. |
| 722 | +Per mantenir la privacitat del votant, els registres d'elecció encriptats només són públicament disponibles quan es poden emetre amb un flux segur de nombres aleatoris.", |
644 | 723 | 'securepoll-translate-title' => 'Traducció: $1', |
645 | 724 | 'securepoll-invalid-language' => "Codi d'idioma «$1» no vàlid", |
646 | 725 | 'securepoll-submit-translate' => 'Actualitza', |
— | — | @@ -651,14 +730,21 @@ |
652 | 731 | 'securepoll-subpage-vote' => 'Votació', |
653 | 732 | 'securepoll-subpage-translate' => 'Traducció', |
654 | 733 | 'securepoll-subpage-list' => 'Llista', |
655 | | - 'securepoll-tally-not-finished' => 'Excuses, les dades de la votació no estaran disponibles fins que hagi finalitzat.', |
| 734 | + 'securepoll-subpage-dump' => 'Abocament', |
| 735 | + 'securepoll-subpage-tally' => 'Compte', |
| 736 | + 'securepoll-tally-title' => 'Compte: $1', |
| 737 | + 'securepoll-tally-not-finished' => 'Les dades de la votació no estaran disponibles fins que hagi finalitzat.', |
656 | 738 | 'securepoll-can-decrypt' => "El registre de l'elecció ha estat encriptat, però la clau de desxifratge està disponible. |
657 | 739 | Podeu triar entre comptar els resultats presents a la base de dades, o de comptar-ne els encriptats a partir d'un fitxer carregat.", |
658 | 740 | 'securepoll-tally-no-key' => "No podeu comptar els vots d'aquesta elecció, perquè estan encriptats i la clau de desxifratge no està disponible.", |
659 | 741 | 'securepoll-tally-local-legend' => 'Comptar els resultats arxivats.', |
660 | 742 | 'securepoll-tally-local-submit' => 'Comptar els vots.', |
| 743 | + 'securepoll-tally-upload-legend' => 'Carrega un abocament encriptat', |
| 744 | + 'securepoll-tally-upload-submit' => 'Crea un compte', |
661 | 745 | 'securepoll-tally-error' => "Error en interpretar l'arxiu de votació, no es poden comptar els resultats.", |
662 | 746 | 'securepoll-no-upload' => "No s'ha carregat cap arxiu, no s'en poden comptar els resultats.", |
| 747 | + 'securepoll-dump-corrupt' => 'El fitxer bolcat es troba danyat i no pot ser processat.', |
| 748 | + 'securepoll-tally-upload-error' => 'Error al contar el fitxer bolcat: $1', |
663 | 749 | ); |
664 | 750 | |
665 | 751 | /** Czech (Česky) |
— | — | @@ -709,6 +795,9 @@ |
710 | 796 | 'securepoll-jump' => 'Přejít na hlasovací server', |
711 | 797 | 'securepoll-bad-ballot-submission' => 'Váš hlas je neplatný: $1', |
712 | 798 | 'securepoll-unanswered-questions' => 'Musíte zodpovědět všechny otázky.', |
| 799 | + 'securepoll-invalid-rank' => 'Neplatné pořadí. Kandidátům musíte přidělit pořadí mezi 1 a 999.', |
| 800 | + 'securepoll-unranked-options' => 'Některé možnosti nebyly ohodnoceny. |
| 801 | +Musíte všem možnostem přidělit pořadí mezi 1 a 999.', |
713 | 802 | 'securepoll-remote-auth-error' => 'Při čtení informací o vašem uživatelském účtu ze serveru nastala chyba.', |
714 | 803 | 'securepoll-remote-parse-error' => 'Při zpracovávání autorizační odpovědi od serveru nastala chyba.', |
715 | 804 | 'securepoll-api-invalid-params' => 'Chybné parametry.', |
— | — | @@ -733,6 +822,7 @@ |
734 | 823 | 'securepoll-strike-reason' => 'Důvod:', |
735 | 824 | 'securepoll-strike-cancel' => 'Storno', |
736 | 825 | 'securepoll-strike-error' => 'Nepodařilo se provést přeškrtnutí či jeho zrušení: $1', |
| 826 | + 'securepoll-strike-token-mismatch' => 'Data z relace byla ztracena', |
737 | 827 | 'securepoll-details-link' => 'Podrobnosti', |
738 | 828 | 'securepoll-details-title' => 'Podrobnosti hlasu #$1', |
739 | 829 | 'securepoll-invalid-vote' => '„$1“ není platný identifikátor hlasu', |
— | — | @@ -748,6 +838,8 @@ |
749 | 839 | 'securepoll-dump-not-finished' => 'Šifrovaný záznam hlasování bude k dispozici až po skončení voleb, $1, $2', |
750 | 840 | 'securepoll-dump-no-urandom' => 'Nelze otevřít <tt>/dev/urandom</tt>. |
751 | 841 | Kvůli tajnosti hlasování je šifrovaný záznam hlasování veřejně dostupný pouze v případě, že hlasy mohou být zamíchány pomocí bezpečného zdroje náhodných čísel.', |
| 842 | + 'securepoll-urandom-not-supported' => 'Tento server nepodporuje kryptografické generování náhodných čísel. |
| 843 | +Kvůli tajnosti hlasování je šifrovaný záznam hlasování veřejně dostupný pouze v případě, že hlasy mohou být zamíchány pomocí bezpečného zdroje náhodných čísel.', |
752 | 844 | 'securepoll-translate-title' => 'Překlad – $1', |
753 | 845 | 'securepoll-invalid-language' => 'Neplatný kód jazyka „$1“', |
754 | 846 | 'securepoll-submit-translate' => 'Uložit', |
— | — | @@ -772,6 +864,8 @@ |
773 | 865 | 'securepoll-tally-upload-submit' => 'Provést sčítání', |
774 | 866 | 'securepoll-tally-error' => 'Chyba při zpracovávání záznamu hlasování, hlasování nelze sečíst.', |
775 | 867 | 'securepoll-no-upload' => 'Nebyl načten žádný soubor, hlasování nelze sečíst.', |
| 868 | + 'securepoll-dump-corrupt' => 'Soubor se záznamem je poškozený a nelze ho zpracovat.', |
| 869 | + 'securepoll-tally-upload-error' => 'Chyba při sčítání záznamu: $1', |
776 | 870 | ); |
777 | 871 | |
778 | 872 | /** Welsh (Cymraeg) |
— | — | @@ -820,10 +914,11 @@ |
821 | 915 | 'securepoll-no-decryption-key' => "Nid yw'r allwedd dadgryptio wedi ei ffurfweddu. |
822 | 916 | Ni ellir dadgryptio.", |
823 | 917 | 'securepoll-jump' => 'Mynd i weinydd y pleidleisio', |
824 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
825 | | -Nid oedd eich pleidlais yn ddilys: $1 |
826 | | -</div>', |
| 918 | + 'securepoll-bad-ballot-submission' => 'Nid oedd eich pleidlais yn ddilys: $1', |
827 | 919 | 'securepoll-unanswered-questions' => 'Rhaid ateb pob cwestiwn.', |
| 920 | + 'securepoll-invalid-rank' => "Gradd annilys yn y drefn restrol. Rhaid ichi roi gradd rhwng 1 a 999 i'r ymgeiswyr.", |
| 921 | + 'securepoll-unranked-options' => 'Gadawyd rhai dewisiadau heb eu rhestru. |
| 922 | +Rhaid ichi roi gradd rhwng 1 a 999 i bob dewis.', |
828 | 923 | 'securepoll-remote-auth-error' => "Cafwyd gwall wrth nôl gwybodaeth eich cyfrif o'r gweinydd.", |
829 | 924 | 'securepoll-remote-parse-error' => "Cafwyd gwall wrth ddehongli ymateb y gweinydd i'r cais awdurdodi.", |
830 | 925 | 'securepoll-api-invalid-params' => 'Paramedrau annilys.', |
— | — | @@ -848,6 +943,7 @@ |
849 | 944 | 'securepoll-strike-reason' => 'Rheswm:', |
850 | 945 | 'securepoll-strike-cancel' => 'Canslo', |
851 | 946 | 'securepoll-strike-error' => 'Gwall wrth geisio annilysu/ail-ddilysu: $1', |
| 947 | + 'securepoll-strike-token-mismatch' => "Collwyd data'r sesiwn", |
852 | 948 | 'securepoll-details-link' => 'Manylion', |
853 | 949 | 'securepoll-details-title' => 'Manylion y bleidlais: #$1', |
854 | 950 | 'securepoll-invalid-vote' => 'Nid yw "$1" yn ID dilys ar gyfer y bleidlais', |
— | — | @@ -863,6 +959,8 @@ |
864 | 960 | 'securepoll-dump-not-finished' => "Ni fydd y cofnodion amgryptiedig o'r etholiad ar gael hyd at ddiwedd yr etholiad am $2 ar $1", |
865 | 961 | 'securepoll-dump-no-urandom' => "Ni ellir agor /dev/urandom. |
866 | 962 | Er mwyn diogelu cyfrinachedd pleidleiswyr, nid yw cofnodion yr etholiad ar gael i'r cyhoedd ond pan y gellir eu cymysgu trwy ddefnyddio llif haprifau diogel.", |
| 963 | + 'securepoll-urandom-not-supported' => "Nid yw'r gweinydd hwn yn gallu cynhyrchu haprifau ar gyfer amgryptio. |
| 964 | +Er mwyn diogelu cyfrinachedd y pleidleiswyr, nid yw cofnodion amgryptiedig yr etholiad ar gael i'r cyhoedd ond pan fo modd eu cymysgu'n ddi-ôl trwy ddefnyddio ffrwd diogel o haprifau.", |
867 | 965 | 'securepoll-translate-title' => 'Cyfieithu: $1', |
868 | 966 | 'securepoll-invalid-language' => 'Côd iaith annilys, "$1"', |
869 | 967 | 'securepoll-submit-translate' => 'Diweddaru', |
— | — | @@ -887,10 +985,13 @@ |
888 | 986 | 'securepoll-tally-upload-submit' => 'Cadw cyfrif', |
889 | 987 | 'securepoll-tally-error' => "Cafwyd gwall wrth ddehongli'r cofnod pleidleisio, ni ellir cadw cyfrif.", |
890 | 988 | 'securepoll-no-upload' => 'Ni uwchlwythwyd unrhyw ffeil, ni ellir cyfrif y canlyniadau.', |
| 989 | + 'securepoll-dump-corrupt' => 'Mae ffeil y dymp yn llygredig ac ni ellir weithredu arno.', |
| 990 | + 'securepoll-tally-upload-error' => 'Cafwyd gwall wrth gyfrif y ffeil dymp: $1', |
891 | 991 | ); |
892 | 992 | |
893 | 993 | /** Danish (Dansk) |
894 | 994 | * @author Kaare |
| 995 | + * @author Masz |
895 | 996 | * @author Sir48 |
896 | 997 | */ |
897 | 998 | $messages['da'] = array( |
— | — | @@ -902,7 +1003,8 @@ |
903 | 1004 | 'securepoll-invalid-election' => '"$1" er ikke en gyldig valg-id.', |
904 | 1005 | 'securepoll-welcome' => '<strong>Velkommen $1!</strong>', |
905 | 1006 | 'securepoll-not-started' => 'Dette valg er endnu ikke begyndt. |
906 | | -Det er planlagt til at begynde den $1.', |
| 1007 | +Det er planlagt til at begynde den $2 klokken $3.', |
| 1008 | + 'securepoll-finished' => 'Dette valg er afsluttet, du kan ikke længere stemme.', |
907 | 1009 | 'securepoll-not-qualified' => 'Du er kvalificeret til at afgive din stemme ved dette valg: $1', |
908 | 1010 | 'securepoll-change-disallowed' => 'Du har allerede afgivet din stemme ved dette valg. |
909 | 1011 | Desværre kan du ikke stemme igen.', |
— | — | @@ -934,11 +1036,29 @@ |
935 | 1037 | 'securepoll-gpg-parse-error' => 'Fejl ved fortolkning af uddata fra GPG.', |
936 | 1038 | 'securepoll-no-decryption-key' => 'Ingen dekrypteringsnøgle opsat. |
937 | 1039 | Kan ikke dekryptere.', |
| 1040 | + 'securepoll-jump' => 'Gå til stemmeserveren', |
| 1041 | + 'securepoll-bad-ballot-submission' => 'Din stemme var ugyldig: $1', |
| 1042 | + 'securepoll-unanswered-questions' => 'Du skal besvare alle spørgsmålene.', |
| 1043 | + 'securepoll-invalid-rank' => 'Ugyldig rangorden. Du skal give kandidaterne en rangorden mellem 1 og 999.', |
| 1044 | + 'securepoll-unranked-options' => 'Nogle muligheder blev ikke rangordnet. |
| 1045 | +Du skal give alle muligheder en rangordning mellem 1 og 999.', |
| 1046 | + 'securepoll-remote-auth-error' => 'Der opstod en fejl under hentning af dine kontoinformationer fra serveren.', |
| 1047 | + 'securepoll-remote-parse-error' => 'Der opstod en fejl under læsning af autorisationssvarene fra serveren.', |
| 1048 | + 'securepoll-api-invalid-params' => 'Ugyldige parametere.', |
| 1049 | + 'securepoll-api-no-user' => 'Ingen brugere med den angivne ID blev fundet.', |
| 1050 | + 'securepoll-api-token-mismatch' => 'Sikkerhedskoden er forkert, du kan ikke logge ind.', |
| 1051 | + 'securepoll-not-logged-in' => 'Du skal logge ind for at stemme i dette valg', |
| 1052 | + 'securepoll-too-few-edits' => 'Beklager, men du kan ikke stemme. Du skal lave mindst $1 {{PLURAL:$1|redigering|redigeringer}}. Du har kun lavet $2.', |
| 1053 | + 'securepoll-blocked' => 'Du kan ikke stemme, fordi du i øjeblikket er blokeret fra at redigere.', |
| 1054 | + 'securepoll-bot' => 'Beklager, men konti med botflag kan ikke stemme i dette valg.', |
| 1055 | + 'securepoll-not-in-group' => 'Kun brugere af gruppen "$1" kan stemme.', |
| 1056 | + 'securepoll-not-in-list' => 'Du er desværre ikke på listen over brugere, som kan stemme i dette valg.', |
938 | 1057 | 'securepoll-list-title' => 'Vis stemmer: $1', |
939 | 1058 | 'securepoll-header-timestamp' => 'Tid', |
940 | 1059 | 'securepoll-header-voter-name' => 'Navn', |
941 | 1060 | 'securepoll-header-voter-domain' => 'Domæne', |
942 | 1061 | 'securepoll-header-ua' => 'Useragent', |
| 1062 | + 'securepoll-header-cookie-dup' => 'Dublet', |
943 | 1063 | 'securepoll-header-strike' => 'Fjern', |
944 | 1064 | 'securepoll-header-details' => 'Oplysninger', |
945 | 1065 | 'securepoll-strike-button' => 'Fjern', |
— | — | @@ -946,6 +1066,7 @@ |
947 | 1067 | 'securepoll-strike-reason' => 'Årsag:', |
948 | 1068 | 'securepoll-strike-cancel' => 'Annuller', |
949 | 1069 | 'securepoll-strike-error' => 'Fejl ved fjernelse eller ophævelse af fjernelse: $1', |
| 1070 | + 'securepoll-strike-token-mismatch' => 'Sessionsdata mistet', |
950 | 1071 | 'securepoll-details-link' => 'Oplysninger', |
951 | 1072 | 'securepoll-details-title' => 'Valgoplysninger: #$1', |
952 | 1073 | 'securepoll-invalid-vote' => '"$1" er ikke en gyldig valg-id', |
— | — | @@ -955,21 +1076,46 @@ |
956 | 1077 | 'securepoll-header-action' => 'Handling', |
957 | 1078 | 'securepoll-header-reason' => 'Årsag', |
958 | 1079 | 'securepoll-header-admin' => 'Admin', |
| 1080 | + 'securepoll-cookie-dup-list' => 'Cooke-dubletbrugere', |
959 | 1081 | 'securepoll-dump-title' => 'Dump: $1', |
960 | 1082 | 'securepoll-dump-no-crypt' => 'Ingen krypterede valgregistreringer er tilgængelige til dette valg, fordi valget ikke er opsat til at anvende kryptering.', |
961 | | - 'securepoll-dump-not-finished' => 'Krypterede valgregistreringer er kun tilgængelige efter den sidste valgdag: $1', |
| 1083 | + 'securepoll-dump-not-finished' => 'Krypterede valgregistreringer er kun tilgængelige efter afstemningen den $1 klokken $2.', |
962 | 1084 | 'securepoll-dump-no-urandom' => 'Kan ikke åbne /dev/urandom. |
963 | 1085 | For at sikre en hemmelig afstemning er de krypterede valgregistrering kun offentligt tilgængelige, når de kan blandes med en sikker strøm af tilfældige tal.', |
| 1086 | + 'securepoll-urandom-not-supported' => 'Denne server understøtter ikke generering af tilfældige kryptografiske tal. |
| 1087 | +For at vedligeholde personlige oplysninger om vælgeren, er krypterede valgregistreringer kun offentligt tilgængelige, når de kan blandes med en strøm af sikre tilfældige tal.', |
964 | 1088 | 'securepoll-translate-title' => 'Oversæt: $1', |
965 | 1089 | 'securepoll-invalid-language' => 'Ugyldig sprogkode "$1"', |
966 | 1090 | 'securepoll-submit-translate' => 'Opdater', |
967 | 1091 | 'securepoll-language-label' => 'Vælg sprog:', |
968 | 1092 | 'securepoll-submit-select-lang' => 'Oversæt', |
| 1093 | + 'securepoll-header-title' => 'Navn', |
| 1094 | + 'securepoll-header-start-date' => 'Startsdato', |
| 1095 | + 'securepoll-header-end-date' => 'Slutsdato', |
| 1096 | + 'securepoll-subpage-vote' => 'Stem', |
| 1097 | + 'securepoll-subpage-translate' => 'Oversæt', |
| 1098 | + 'securepoll-subpage-list' => 'Liste', |
| 1099 | + 'securepoll-subpage-dump' => 'Dump', |
| 1100 | + 'securepoll-subpage-tally' => 'Optælling', |
| 1101 | + 'securepoll-tally-title' => 'Optælling: $1', |
| 1102 | + 'securepoll-tally-not-finished' => 'Du kan desværre ikke optælle valgresultatet før afstemningen er slut.', |
| 1103 | + 'securepoll-can-decrypt' => 'Valgregisteret er blevet krypteret, men en dekrypteringsnøgle er tilgængelig. |
| 1104 | +Du kan enten optælle de nuværende stemmer i databasen, eller optælle krypterede resultater fra et oplagt fil.', |
| 1105 | + 'securepoll-tally-no-key' => 'Du kan ikke tælle resultatet op, fordi stemmerne er krypterede, og dekrypteringsnøglen er utilgængelig.', |
| 1106 | + 'securepoll-tally-local-legend' => 'Optællig af stemmerne', |
| 1107 | + 'securepoll-tally-local-submit' => 'Opret en optælling', |
| 1108 | + 'securepoll-tally-upload-legend' => 'Læg en krypteret dump op', |
| 1109 | + 'securepoll-tally-upload-submit' => 'Opret optælling', |
| 1110 | + 'securepoll-tally-error' => 'Fejl under læsning af stemmeregisteret, kan ikke oprette en optælling.', |
| 1111 | + 'securepoll-no-upload' => 'Ingen fil blev lagt op; kan ikke tælle resultatet op.', |
| 1112 | + 'securepoll-dump-corrupt' => 'Dumpfilen er korrupt og kan ikke behandles.', |
| 1113 | + 'securepoll-tally-upload-error' => 'Fejl ved optælling af dumpfilen: $1', |
969 | 1114 | ); |
970 | 1115 | |
971 | 1116 | /** German (Deutsch) |
972 | 1117 | * @author ChrisiPK |
973 | 1118 | * @author Metalhead64 |
| 1119 | + * @author Pill |
974 | 1120 | * @author Umherirrender |
975 | 1121 | */ |
976 | 1122 | $messages['de'] = array( |
— | — | @@ -1017,6 +1163,9 @@ |
1018 | 1164 | 'securepoll-jump' => 'Gehe zum Abstimmungsserver', |
1019 | 1165 | 'securepoll-bad-ballot-submission' => 'Deine Stimme war ungültig: $1', |
1020 | 1166 | 'securepoll-unanswered-questions' => 'Du musst alle Fragen beantworten.', |
| 1167 | + 'securepoll-invalid-rank' => 'Ungültige Rangfolge. Du musst den Kandidaten eine Rangnummer zwischen 1 und 999 geben.', |
| 1168 | + 'securepoll-unranked-options' => 'Einige Optionen wurden nicht mit einer Rangnummer versehen. |
| 1169 | +Du musst allen Optionen eine Rangnummer zwischen 1 und 999 geben.', |
1021 | 1170 | 'securepoll-remote-auth-error' => 'Fehler beim Abruf deiner Benutzerkonteninformationen vom Server.', |
1022 | 1171 | 'securepoll-remote-parse-error' => 'Fehler beim Interpretieren der Berechtigungsantwort des Servers.', |
1023 | 1172 | 'securepoll-api-invalid-params' => 'Ungültige Parameter.', |
— | — | @@ -1041,6 +1190,7 @@ |
1042 | 1191 | 'securepoll-strike-reason' => 'Grund:', |
1043 | 1192 | 'securepoll-strike-cancel' => 'Abbrechen', |
1044 | 1193 | 'securepoll-strike-error' => 'Fehler bei der Streichung/Streichungsrücknahme: $1', |
| 1194 | + 'securepoll-strike-token-mismatch' => 'Sitzungsdaten verloren', |
1045 | 1195 | 'securepoll-details-link' => 'Details', |
1046 | 1196 | 'securepoll-details-title' => 'Abstimmungsdetails: #$1', |
1047 | 1197 | 'securepoll-invalid-vote' => '„$1“ ist keine gültige Abstimmungs-ID', |
— | — | @@ -1056,6 +1206,8 @@ |
1057 | 1207 | 'securepoll-dump-not-finished' => 'Verschlüsselte Abstimmungsaufzeichnungen sind nur nach dem Endtermin am $1 um $2 Uhr verfügbar', |
1058 | 1208 | 'securepoll-dump-no-urandom' => '/dev/urandom kann nicht geöffnet werden. |
1059 | 1209 | Um den Wählerdatenschutz zu wahren, sind verschlüsselte Abstimmungsaufzeichnungen nur öffentlich verfügbar, wenn sie mit einem sicheren Zufallszahlenstrom gemischt werden können.', |
| 1210 | + 'securepoll-urandom-not-supported' => 'Dieser Server unterstützt keine kryptographische Zufallszahlenerzeugung. |
| 1211 | +Zur Sicherstellung des Wahlgeheimnisses sind verschlüsselte Wahlaufzeichnungen nur öffentlich verfügbar, sofern sie mit einer sicheren Zufallszahlenreihenfolge vermischt werden konnten.', |
1060 | 1212 | 'securepoll-translate-title' => 'Übersetzen: $1', |
1061 | 1213 | 'securepoll-invalid-language' => 'Ungültiger Sprachcode „$1“', |
1062 | 1214 | 'securepoll-submit-translate' => 'Aktualisieren', |
— | — | @@ -1080,6 +1232,10 @@ |
1081 | 1233 | 'securepoll-tally-upload-submit' => 'Zählung erstellen', |
1082 | 1234 | 'securepoll-tally-error' => 'Fehler beim Interpretieren der Abstimmungsaufzeichnung, Auszählungserstellung nicht möglich.', |
1083 | 1235 | 'securepoll-no-upload' => 'Es wurde keine Datei hochgeladen, Ergebniszählung nicht möglich.', |
| 1236 | + 'securepoll-dump-corrupt' => 'Die Dump-Datei ist korrupt und kann nicht verarbeitet werden.', |
| 1237 | + 'securepoll-tally-upload-error' => 'Fehler beim Zählen der Dump-Datei: $1', |
| 1238 | + 'securepoll-pairwise-victories' => 'Paarweise Siegesmatrix', |
| 1239 | + 'securepoll-ranks' => 'Schlussranking', |
1084 | 1240 | ); |
1085 | 1241 | |
1086 | 1242 | /** German (formal address) (Deutsch (Sie-Form)) |
— | — | @@ -1164,6 +1320,9 @@ |
1165 | 1321 | 'securepoll-jump' => 'K serweroju wótgłosowanja', |
1166 | 1322 | 'securepoll-bad-ballot-submission' => 'Twój głos jo njepłaśiwy był: $1', |
1167 | 1323 | 'securepoll-unanswered-questions' => 'Musyš na wše pšašanja wótegroniś.', |
| 1324 | + 'securepoll-invalid-rank' => 'Njepłaśiwe pódaśe pozicije. Dejš kandidatam poziciju mjazy 1 a 999 daś.', |
| 1325 | + 'securepoll-unranked-options' => 'Někotare opcije njamaju pódaśe pozicije. |
| 1326 | +Dejš wšyknym opcijam pódaśe pozicije mjazy 1 a 999 daś.', |
1168 | 1327 | 'securepoll-remote-auth-error' => 'Zmólka pśi wótwołowanju twójich kontowych informacijow ze serwera.', |
1169 | 1328 | 'securepoll-remote-parse-error' => 'Zmólka pśi interpretěrowanju awtorizěrowańskego wótegrona serwera.', |
1170 | 1329 | 'securepoll-api-invalid-params' => 'Njepłaśiwe parametry.', |
— | — | @@ -1188,6 +1347,7 @@ |
1189 | 1348 | 'securepoll-strike-reason' => 'Pśicyna:', |
1190 | 1349 | 'securepoll-strike-cancel' => 'Pśetergnuś', |
1191 | 1350 | 'securepoll-strike-error' => 'Zmólka pśi wušmarnjenju/anulěrowanju wušmarnjenja: $1', |
| 1351 | + 'securepoll-strike-token-mismatch' => 'Daty pósejźenja su se zgubili', |
1192 | 1352 | 'securepoll-details-link' => 'Drobnostki', |
1193 | 1353 | 'securepoll-details-title' => 'Wótgłosowańske drobnostki: #$1', |
1194 | 1354 | 'securepoll-invalid-vote' => '"$1" njejo płaśiwy wótgłosowański ID', |
— | — | @@ -1230,11 +1390,14 @@ |
1231 | 1391 | ); |
1232 | 1392 | |
1233 | 1393 | /** Greek (Ελληνικά) |
| 1394 | + * @author Assassingr |
| 1395 | + * @author Badseed |
1234 | 1396 | * @author Consta |
1235 | 1397 | * @author Crazymadlover |
1236 | 1398 | * @author Geraki |
1237 | 1399 | * @author Omnipaedista |
1238 | 1400 | * @author ZaDiak |
| 1401 | + * @author Απεργός |
1239 | 1402 | */ |
1240 | 1403 | $messages['el'] = array( |
1241 | 1404 | 'securepoll' => 'SecurePoll', |
— | — | @@ -1243,13 +1406,13 @@ |
1244 | 1407 | 'securepoll-need-admin' => 'Πρέπει να είστε διαχειριστής για να κάνετε αυτή την ενέργεια.', |
1245 | 1408 | 'securepoll-too-few-params' => 'Μη αρκετές παράμετροι υποσελίδας (άκυρος σύνδεσμος).', |
1246 | 1409 | 'securepoll-invalid-election' => '"$1" δεν είναι ένα αποδεκτό ID ψηφοφορίας.', |
1247 | | - 'securepoll-welcome' => '<strong>Καλωσήρθες $1!</strong>', |
| 1410 | + 'securepoll-welcome' => '<strong>Καλωσήρθατε $1!</strong>', |
1248 | 1411 | 'securepoll-not-started' => 'Η ψηφοφορία δεν έχει ξεκινήσει ακόμη. |
1249 | 1412 | Είναι προγραμματισμένη να ξεκινήσει στις $2 στις $3.', |
1250 | 1413 | 'securepoll-finished' => 'Αυτή η ψηφοφορία έχει τελειώσει, δεν μπορείτε πλέον να ψηφίσετε.', |
1251 | 1414 | 'securepoll-not-qualified' => 'Δεν καλύπτετε τα κριτήρια για να ψηφίσετε σε αυτή την ψηφοφορία: $1', |
1252 | 1415 | 'securepoll-change-disallowed' => 'Έχετε ψηφίσει προηγουμένως σε αυτή την ψηφοφορία. |
1253 | | -Συγνώμη, δεν μπορείτε να ψηφίσετε ξανά.', |
| 1416 | +Λυπούμαστε, δεν μπορείτε να ψηφίσετε ξανά.', |
1254 | 1417 | 'securepoll-change-allowed' => '<strong>Σημείωση: Έχετε ψηφίσει προηγουμένως σε αυτή την ψηφοφορία.</strong> |
1255 | 1418 | Μπορείτε να αλλάξετε την ψήφο σας αποστέλλοντας την φόρμα παρακάτω. |
1256 | 1419 | Λάβετε υπόψη ότι αν κάνετε αυτό, η αρχική ψήφος σας θα ακυρωθεί.', |
— | — | @@ -1260,12 +1423,12 @@ |
1261 | 1424 | |
1262 | 1425 | <pre>$1</pre>', |
1263 | 1426 | 'securepoll-thanks' => 'Ευχαριστούμε, η ψήφος σας καταγράφηκε.', |
1264 | | - 'securepoll-return' => 'Επιστροφή στην $1', |
1265 | | - 'securepoll-encrypt-error' => 'Αποτυχία κρυπτογράφησης της καταγραφής ψήφου σας. |
| 1427 | + 'securepoll-return' => 'Επιστροφή στη σελίδα $1', |
| 1428 | + 'securepoll-encrypt-error' => 'Αποτυχία κρυπτογράφησης της εγγραφής ψήφου σας. |
1266 | 1429 | Η ψήφος σας δεν έχει καταγραφεί! |
1267 | 1430 | |
1268 | 1431 | $1', |
1269 | | - 'securepoll-no-gpg-home' => 'Αποτυχία δημιουργίας οικείου καταλόγου GPG.', |
| 1432 | + 'securepoll-no-gpg-home' => 'Αποτυχία δημιουργίας καταλόγου αρχείων του GPG.', |
1270 | 1433 | 'securepoll-secret-gpg-error' => 'Σφάλμα εκτέλεσης GPG. |
1271 | 1434 | Χρησιμοποιήστε $wgSecurePollShowErrorDetail=true; στο LocalSettings.php για εμφάνιση περισσότερων λεπτομερειών.', |
1272 | 1435 | 'securepoll-full-gpg-error' => 'Σφάλμα εκτέλεσης GPG: |
— | — | @@ -1279,19 +1442,20 @@ |
1280 | 1443 | 'securepoll-no-decryption-key' => 'Δεν έχει ρυθμιστεί κλειδί αποκρυπτογράφησης. |
1281 | 1444 | Δεν είναι δυνατή η αποκρυπτογράφηση.', |
1282 | 1445 | 'securepoll-jump' => 'Μετάβαση στον διακομιστή ψηφοφορίας', |
1283 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
1284 | | -Η ψήφος σας ήταν άκυρη: $1 |
1285 | | -</div>', |
1286 | | - 'securepoll-unanswered-questions' => 'Πρέπει να απαντήσεις σε όλες τις ερωτήσεις.', |
| 1446 | + 'securepoll-bad-ballot-submission' => 'Η ψήφος σας ήταν άκυρη: $1', |
| 1447 | + 'securepoll-unanswered-questions' => 'Πρέπει να απαντήσετε σε όλες τις ερωτήσεις.', |
| 1448 | + 'securepoll-invalid-rank' => 'Εσφαλμένη κατάταξη. Πρέπει να δώσετε στους υποψηφίους μια κατάταξη μεταξύ 1 και 999.', |
| 1449 | + 'securepoll-unranked-options' => 'Ορισμένες επιλογές δεν κατατάχθηκαν. |
| 1450 | +Πρέπει να δώσετε σε όλες τις επιλογές μια κατάταξη μεταξύ 1 και 999.', |
1287 | 1451 | 'securepoll-remote-auth-error' => 'Σφάλμα κατά την ανάκτηση των πληροφοριών για τον λογαριασμό σας από τον διακομιστή.', |
1288 | 1452 | 'securepoll-remote-parse-error' => 'Σφάλμα στην ερμηνεία της απάντησης για άδεια πρόβασης από τον διακομιστή.', |
1289 | | - 'securepoll-api-invalid-params' => 'Άκυροι παράμετροι.', |
1290 | | - 'securepoll-api-no-user' => 'Δεν βρέθηκε χρήστης με αυτό το ID.', |
1291 | | - 'securepoll-api-token-mismatch' => 'Μη ταυτοποίηση κλειδιού ασφαλείας, δεν μπορείτε να συνδεθείτε.', |
1292 | | - 'securepoll-not-logged-in' => 'Πρέπει να συνδεθείτε για να ψηφίσετε στις εκλογές', |
1293 | | - 'securepoll-too-few-edits' => 'Συγνώμη, δεν μπορείτε να ψηφίσετε. Χρειάζεται να έχετε κάνει τουλάχιστον $1 {{PLURAL:$1|επεξεργασία|επεξεργασίες}} για να ψηφίσετε σε αυτή την ψηφοφορία, έχετε κάνει $2.', |
1294 | | - 'securepoll-blocked' => 'Συγνώμη δεν μπορείτε να ψηφίσετε σε αυτή την ψηφοφορία αν είστε επί του παρόντος υπό φραγή από την επεξεργασία.', |
1295 | | - 'securepoll-bot' => 'Συγνώμη, οι λογαριασμοί με σημαία μποτ δεν επιτρέπεται να ψηφίσουν σε αυτήν την ψηφοφορία.', |
| 1453 | + 'securepoll-api-invalid-params' => 'Άκυρες παράμετροι.', |
| 1454 | + 'securepoll-api-no-user' => 'Δεν βρέθηκε χρήστης με το συγκεκριμένο ID.', |
| 1455 | + 'securepoll-api-token-mismatch' => 'Μη ταυτοποίηση κουπονιού ασφαλείας, δεν μπορείτε να συνδεθείτε.', |
| 1456 | + 'securepoll-not-logged-in' => 'Πρέπει να συνδεθείτε για να ψηφίσετε σε αυτές τις εκλογές', |
| 1457 | + 'securepoll-too-few-edits' => 'Λυπούμαστε, δεν μπορείτε να ψηφίσετε. Χρειάζεται να έχετε κάνει τουλάχιστον $1 {{PLURAL:$1|επεξεργασία|επεξεργασίες}} για να ψηφίσετε σε αυτή την ψηφοφορία, έχετε κάνει $2.', |
| 1458 | + 'securepoll-blocked' => 'Λυπούμαστε, δεν μπορείτε να ψηφίσετε σε αυτή την ψηφοφορία αν είστε επί του παρόντος υπό φραγή από την επεξεργασία.', |
| 1459 | + 'securepoll-bot' => 'Λυπούμαστε, οι λογαριασμοί με ιδιότητα bot δεν επιτρέπεται να ψηφίσουν σε αυτήν την ψηφοφορία.', |
1296 | 1460 | 'securepoll-not-in-group' => "Μόνο τα μέλη της ομάδας $1 μπορούν να ψηφίσουν σ' αυτές τις εκλογές.", |
1297 | 1461 | 'securepoll-not-in-list' => 'Λυπούμαστε, αλλά δεν βρίσκεστε στην προκαθορισμένη λίστα χρηστών που επιτρέπεται να ψηφίσουν στις εκλογές αυτές.', |
1298 | 1462 | 'securepoll-list-title' => 'Λίστα ψήφων: $1', |
— | — | @@ -1300,26 +1464,30 @@ |
1301 | 1465 | 'securepoll-header-voter-domain' => 'Περιοχή', |
1302 | 1466 | 'securepoll-header-ua' => 'Αντιπρόσωπος χρήστη', |
1303 | 1467 | 'securepoll-header-cookie-dup' => 'Διπλότυπες', |
1304 | | - 'securepoll-header-strike' => 'Σβήσιμο', |
| 1468 | + 'securepoll-header-strike' => 'Διαγραφή', |
1305 | 1469 | 'securepoll-header-details' => 'Λεπτομέρειες', |
1306 | | - 'securepoll-strike-button' => 'Σβήσιμο', |
1307 | | - 'securepoll-unstrike-button' => 'Ακύρωση σβησίματος', |
| 1470 | + 'securepoll-strike-button' => 'Διαγραφή', |
| 1471 | + 'securepoll-unstrike-button' => 'Αναίρεση διαγραφής', |
1308 | 1472 | 'securepoll-strike-reason' => 'Λόγος:', |
1309 | 1473 | 'securepoll-strike-cancel' => 'Άκυρο', |
1310 | | - 'securepoll-strike-error' => 'Σφάλμα κατά το σβήσιμο/την αναίρεση σβησίματος: $1', |
| 1474 | + 'securepoll-strike-error' => 'Σφάλμα κατά τη διαγραφή/την αναίρεση διαγραφής: $1', |
| 1475 | + 'securepoll-strike-token-mismatch' => 'Χάθηκαν τα δεδομένα συνεδρίας', |
1311 | 1476 | 'securepoll-details-link' => 'Λεπτομέρειες', |
1312 | | - 'securepoll-details-title' => 'Πληροφορίες ψήφου: #$1', |
1313 | | - 'securepoll-invalid-vote' => 'Η "$1" δεν είναι μια έγκυρη ψήφος βάση ταυτότητας', |
| 1477 | + 'securepoll-details-title' => 'Λεπτομέρειες ψήφου: #$1', |
| 1478 | + 'securepoll-invalid-vote' => 'Το "$1" δεν είναι έγκυρο ID ψήφου', |
1314 | 1479 | 'securepoll-header-voter-type' => 'Τύπος ψηφοφόρου', |
1315 | 1480 | 'securepoll-voter-properties' => 'Ιδιότητες ψηφοφόρου', |
1316 | | - 'securepoll-strike-log' => 'Ιστορικό σβησιμάτων', |
| 1481 | + 'securepoll-strike-log' => 'Καταγραφές διαγραφών', |
1317 | 1482 | 'securepoll-header-action' => 'Ενέργεια', |
1318 | 1483 | 'securepoll-header-reason' => 'Λόγος', |
1319 | 1484 | 'securepoll-header-admin' => 'Διαχειριστής', |
1320 | 1485 | 'securepoll-cookie-dup-list' => 'Χρήστες που έχουν διπλότυπο cookie', |
1321 | | - 'securepoll-dump-title' => 'Διπλότυπες: $1', |
1322 | | - 'securepoll-dump-no-crypt' => 'Κανένα κρυπτογραφημένο εκλογικό αρχείο δεν είναι διαθέσιμο για αυτήν την εκλογή, επειδή αυτή δεν είναι διαμορφωμένη για χρήση κρυπτογράφησης.', |
| 1486 | + 'securepoll-dump-title' => 'Αποτύπωση: $1', |
| 1487 | + 'securepoll-dump-no-crypt' => 'Κανένα κρυπτογραφημένο εκλογικό αρχείο δεν είναι διαθέσιμο για αυτήν την εκλογή, επειδή αυτή δεν είναι ρυθμισμένη για χρήση κρυπτογράφησης.', |
1323 | 1488 | 'securepoll-dump-not-finished' => 'Τα κρυπτογραφημένα αρχεία των εκλογών θα είναι μόνο διαθέσιμα μετά την τελευταία μέρα της ψηφοφορίας την $1 στις $2', |
| 1489 | + 'securepoll-dump-no-urandom' => 'Αδύνατο το άνοιγμα του /dev/urandom. |
| 1490 | +Για να διατηρηθεί η ιδιωτικότητα των ψηφοφόρων, οι κρυπτογραφημένες εγγραφές της ψηφοφορίας γίνονται δημόσια διαθέσιμες μόνο όταν μπορούν να ανακατευτούν με μια ασφαλή ακολουθία τυχαίων αριθμών.', |
| 1491 | + 'securepoll-urandom-not-supported' => 'Αυτός ο διακομιστής δεν υποστηρίζει την κρυπτογραφικά ασφαλή παραγωγή τυχαίων αριθμών. Για να διατηρηθεί η ιδιωτικότητα των ψηφοφόρων, οι κρυπτογραφημένες εγγραφές γίνονται δημόσια διαθέσιμες μόνο όταν μπορούν να ανακατευτούν με μία ασφαλή ακολουθία τυχαίων αριθμών.', |
1324 | 1492 | 'securepoll-translate-title' => 'Μετάφραση: $1', |
1325 | 1493 | 'securepoll-invalid-language' => 'Άκυρος κώδικας γλώσσας "$1"', |
1326 | 1494 | 'securepoll-submit-translate' => 'Ενημέρωση', |
— | — | @@ -1328,23 +1496,28 @@ |
1329 | 1497 | 'securepoll-header-title' => 'Όνομα', |
1330 | 1498 | 'securepoll-header-start-date' => 'Ημερομηνία έναρξης', |
1331 | 1499 | 'securepoll-header-end-date' => 'Ημερομηνία λήξης', |
1332 | | - 'securepoll-subpage-vote' => 'Ψήφος', |
| 1500 | + 'securepoll-subpage-vote' => 'Ψηφοφορία', |
1333 | 1501 | 'securepoll-subpage-translate' => 'Μετάφραση', |
1334 | 1502 | 'securepoll-subpage-list' => 'Λίστα', |
1335 | | - 'securepoll-subpage-dump' => 'Διπλότυπες', |
| 1503 | + 'securepoll-subpage-dump' => 'Αποτύπωση', |
1336 | 1504 | 'securepoll-subpage-tally' => 'Καταμέτρηση', |
1337 | 1505 | 'securepoll-tally-title' => 'Καταμέτρηση: $1', |
1338 | | - 'securepoll-tally-not-finished' => 'Συγγνώμη, δεν είναι δυνατή η καταμέτρηση των ψήφων μέχρι να ολοκληρωθεί η ψηφοφορία.', |
1339 | | - 'securepoll-tally-no-key' => 'Δεν μπορείτε να διεξάγετε ψηφομέτρηση σε αυτές τις εκλογές διότι οι ψήφοι είναι κρυπτογραφημένες και το κλειδί αποκρυπτογράφησης δεν είναι διαθέσιμο.', |
1340 | | - 'securepoll-tally-local-legend' => 'Καταμέτρηση αποκατεστημένων αποτελεσμάτων', |
| 1506 | + 'securepoll-tally-not-finished' => 'Λυπούμαστε, δεν είναι δυνατή η καταμέτρηση των ψήφων μέχρι να ολοκληρωθεί η ψηφοφορία.', |
| 1507 | + 'securepoll-can-decrypt' => 'Η εγγραφή ψηφοφορίας έχει κρυποτογραφηθεί, αλλά το κλειδί αποκρυπτογράφησης είναι διαθέσιμο. |
| 1508 | +Μπορείτε να επιλέξετε είτε να καταμετρήσετε τα αποτελέσματα που υπάρχουν στη βάση δεδομένων ή να καταμετρήσετε κρυπτογραφημένα αποτελέσματα από ένα επιφορτωμένο αρχείο.', |
| 1509 | + 'securepoll-tally-no-key' => 'Δεν μπορείτε να καταμετρήσετε τις ψήφους σε αυτές τις εκλογές διότι οι ψήφοι είναι κρυπτογραφημένες και το κλειδί αποκρυπτογράφησης δεν είναι διαθέσιμο.', |
| 1510 | + 'securepoll-tally-local-legend' => 'Καταμέτρηση αποθηκευμένων αποτελεσμάτων', |
1341 | 1511 | 'securepoll-tally-local-submit' => 'Δημιουργία καταμέτρησης', |
1342 | | - 'securepoll-tally-upload-legend' => 'Επιφόρτωση κρυπτογραφημένης διπλότυπης', |
| 1512 | + 'securepoll-tally-upload-legend' => 'Επιφόρτωση κρυπτογραφημένου αρχείου ψήφων', |
1343 | 1513 | 'securepoll-tally-upload-submit' => 'Δημιουργία καταμέτρησης', |
1344 | 1514 | 'securepoll-tally-error' => 'Σφάλμα κατά την ερμηνεία του αρχείου ψήφων· αδύνατη η καταμέτρηση.', |
1345 | 1515 | 'securepoll-no-upload' => 'Κανένα αρχείο δεν επιφορτίστηκε· τα αποτελέσματα δεν μπορούν να καταμετρηθούν', |
| 1516 | + 'securepoll-dump-corrupt' => 'Το αρχείο ψήφων είναι κατεστραμμένο και δεν μπορεί να υποστεί επεξεργασία.', |
| 1517 | + 'securepoll-tally-upload-error' => 'Σφάλμα στην καταμέτρηση του αρχείου ψήφων: $1', |
1346 | 1518 | ); |
1347 | 1519 | |
1348 | 1520 | /** Esperanto (Esperanto) |
| 1521 | + * @author ArnoLagrange |
1349 | 1522 | * @author Yekrats |
1350 | 1523 | */ |
1351 | 1524 | $messages['eo'] = array( |
— | — | @@ -1390,14 +1563,16 @@ |
1391 | 1564 | 'securepoll-no-decryption-key' => 'Neniu malĉifra ŝlosilo estas konfigurita. |
1392 | 1565 | Ne eblas malĉifri.', |
1393 | 1566 | 'securepoll-jump' => 'Iri al la voĉdona servilo', |
1394 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
1395 | | -Via voĉdono estis malvalida: $1 |
1396 | | -</div>', |
| 1567 | + 'securepoll-bad-ballot-submission' => 'Via voĉdono estis malvalida: $1', |
1397 | 1568 | 'securepoll-unanswered-questions' => 'Vi devas respondi al ĉiuj demandoj.', |
| 1569 | + 'securepoll-invalid-rank' => 'Nevalida loko. Vi devas doni al kandidatoj lokon inter 1 kaj 999.', |
| 1570 | + 'securepoll-unranked-options' => 'Kelkaj opcioj ne estis ordigitaj. |
| 1571 | +Vi devas doni al ĉiuj opcioj lokon inter 1 kaj 999.', |
1398 | 1572 | 'securepoll-remote-auth-error' => 'Eraro akirante vian kontinformon de la servilo.', |
1399 | 1573 | 'securepoll-remote-parse-error' => 'Eraro interpretante la aŭtoritadan respondon de la servilo.', |
1400 | 1574 | 'securepoll-api-invalid-params' => 'Malvalidaj parametroj.', |
1401 | 1575 | 'securepoll-api-no-user' => 'Neniu uzanto estis trovita kun tiu identigo.', |
| 1576 | + 'securepoll-api-token-mismatch' => 'Nekongrua sekurecmarkilo. Neeblas ensaluti.', |
1402 | 1577 | 'securepoll-not-logged-in' => 'Vi devas ensaluti por voĉdoni en ĉi tiu voĉdonado', |
1403 | 1578 | 'securepoll-too-few-edits' => 'Bedaŭrinde, vi ne povas voĉdoni. Vi nepre havas almenaŭ $1 {{PLURAL:$1|redakto|redaktoj}} por voĉdoni en ĉi tiu voĉdonado; vi faris $2 redaktojn.', |
1404 | 1579 | 'securepoll-blocked' => 'Bedaŭrinde, vi ne povas voĉdoni en ĉi tiu voĉdonado se vi nune estas forbarita de redaktado.', |
— | — | @@ -1417,6 +1592,7 @@ |
1418 | 1593 | 'securepoll-strike-reason' => 'Kialo:', |
1419 | 1594 | 'securepoll-strike-cancel' => 'Nuligi', |
1420 | 1595 | 'securepoll-strike-error' => 'Eraro farante forstrekadon/malforstrekadon: $1', |
| 1596 | + 'securepoll-strike-token-mismatch' => 'Sesiaj datenoj perditaj', |
1421 | 1597 | 'securepoll-details-link' => 'Detaloj', |
1422 | 1598 | 'securepoll-details-title' => 'Detaloj de voĉdono: #$1', |
1423 | 1599 | 'securepoll-invalid-vote' => '"$1" ne estas valida voĉdona identigo', |
— | — | @@ -1427,6 +1603,13 @@ |
1428 | 1604 | 'securepoll-header-reason' => 'Kialo', |
1429 | 1605 | 'securepoll-header-admin' => 'Administranto', |
1430 | 1606 | 'securepoll-cookie-dup-list' => 'Uzi seancan kuketon por duplikataj uzantoj', |
| 1607 | + 'securepoll-dump-title' => 'Elŝuto: $1', |
| 1608 | + 'securepoll-dump-no-crypt' => 'Neniu ĉifrita registraĵo havebla por tiu ĉi baloto, ĉar la baloto ne estas aranĝita por uzi ĉifradon.', |
| 1609 | + 'securepoll-dump-not-finished' => 'Ĉifrita registraĵo estos havebla por tiu ĉi baloto nur post la findato $1 je $2', |
| 1610 | + 'securepoll-dump-no-urandom' => 'Ne eblas malfermi /dev/urandom |
| 1611 | +Por garantii privatecon de balotinto, ĉifrita balotregistraĵo estas publike havebla nur kiam ĝi povas esti malnetigita per sekura hazarda nombrofluo.', |
| 1612 | + 'securepoll-urandom-not-supported' => 'Ĉi tiu servilo ne eltenas generadon de ĉifrhazardnombroj. |
| 1613 | +Por garantii privatecon de balotinto, ĉifrita balotregistraĵo estas publike havebla nur kiam ĝi povas esti malnetigita per sekura hazarda nombrofluo.', |
1431 | 1614 | 'securepoll-translate-title' => 'Traduki: $1', |
1432 | 1615 | 'securepoll-invalid-language' => 'Malvalida lingva kodo "$1"', |
1433 | 1616 | 'securepoll-submit-translate' => 'Ĝisdatigi', |
— | — | @@ -1438,15 +1621,29 @@ |
1439 | 1622 | 'securepoll-subpage-vote' => 'Voĉdono', |
1440 | 1623 | 'securepoll-subpage-translate' => 'Traduki', |
1441 | 1624 | 'securepoll-subpage-list' => 'Listigi', |
| 1625 | + 'securepoll-subpage-dump' => 'Elŝuto', |
1442 | 1626 | 'securepoll-subpage-tally' => 'Kalkuli', |
1443 | 1627 | 'securepoll-tally-title' => 'Kalkulo: $1', |
1444 | 1628 | 'securepoll-tally-not-finished' => 'Bedaŭrinde vi ne povas kalkuli la voĉdonado ĝis post voĉdonado finas.', |
| 1629 | + 'securepoll-can-decrypt' => 'La balotregistraĵo estis ĉifita, sed la malĉifra ŝlosilo haveblas. |
| 1630 | +Vi povas elekti nombri ĉu la rezultojn el la datumbazo, ĉu ĉifritajn rezultojn el elŝutita dosiero.', |
| 1631 | + 'securepoll-tally-no-key' => 'Vi ne povas nombri la rezulton de ĉi tiu baloto, ĉar ĝi estas ĉifrita kaj la malĉifra ŝlosilo malhaveblas.', |
| 1632 | + 'securepoll-tally-local-legend' => 'Konservitaj nombrorezultoj', |
| 1633 | + 'securepoll-tally-local-submit' => 'Krei nombradon', |
| 1634 | + 'securepoll-tally-upload-legend' => 'Elŝuti ĉifritan dosieron', |
| 1635 | + 'securepoll-tally-upload-submit' => 'Krei nombradon', |
| 1636 | + 'securepoll-tally-error' => 'Eraro dum interpretado de balotregistraĵo, ne eblas krei nombradon.', |
| 1637 | + 'securepoll-no-upload' => 'Neniu dosiero estis elŝutita, ne eblas nombri rezulton.', |
| 1638 | + 'securepoll-dump-corrupt' => 'La elŝutdosiero estas difektita kaj ne povas esti traktita.', |
| 1639 | + 'securepoll-tally-upload-error' => 'Eraro dum nombrado de elŝutdosiero: $1', |
1445 | 1640 | ); |
1446 | 1641 | |
1447 | 1642 | /** Spanish (Español) |
1448 | 1643 | * @author Crazymadlover |
1449 | 1644 | * @author Dferg |
1450 | 1645 | * @author DoveBirkoff |
| 1646 | + * @author Galio |
| 1647 | + * @author Góngora |
1451 | 1648 | * @author Remember the dot |
1452 | 1649 | */ |
1453 | 1650 | $messages['es'] = array( |
— | — | @@ -1456,7 +1653,7 @@ |
1457 | 1654 | 'securepoll-need-admin' => 'Necesitas ser un administrador para realizar esta acción.', |
1458 | 1655 | 'securepoll-too-few-params' => 'Parámetros de subpágina insuficientes (vínculo inválido).', |
1459 | 1656 | 'securepoll-invalid-election' => '"$1" no es un identificador de elección valido.', |
1460 | | - 'securepoll-welcome' => '<strong>Bienvenido $1!</strong>', |
| 1657 | + 'securepoll-welcome' => '<strong>¡Bienvenido $1!</strong>', |
1461 | 1658 | 'securepoll-not-started' => 'Esta elección aún no ha comenzado. |
1462 | 1659 | Está programada de comenzar en $2 de $3.', |
1463 | 1660 | 'securepoll-finished' => 'Esta elección ha concluido, no puedes votar más.', |
— | — | @@ -1478,6 +1675,7 @@ |
1479 | 1676 | ¡Tu voto no ha sido registrado! |
1480 | 1677 | |
1481 | 1678 | $1', |
| 1679 | + 'securepoll-no-gpg-home' => 'Imposible crear un directorio hogar GPG.', |
1482 | 1680 | 'securepoll-secret-gpg-error' => 'Error ejecutando GPG. |
1483 | 1681 | Usar $wgSecurePollShowErrorDetail=true; en LocalSettings.php para mostrar más detalle.', |
1484 | 1682 | 'securepoll-full-gpg-error' => 'Error ejecutando GPG: |
— | — | @@ -1488,14 +1686,23 @@ |
1489 | 1687 | <pre>$2</pre>', |
1490 | 1688 | 'securepoll-gpg-config-error' => 'Teclas GPG están configuradas incorrectamente.', |
1491 | 1689 | 'securepoll-gpg-parse-error' => 'Error interpretando salida GPG.', |
| 1690 | + 'securepoll-no-decryption-key' => 'No se ha especificado ninguna clave de desencriptación. |
| 1691 | +No se puede desencriptar.', |
1492 | 1692 | 'securepoll-jump' => 'Ir al servidor de votación', |
1493 | 1693 | 'securepoll-bad-ballot-submission' => 'Tu voto fue inválido: $1', |
1494 | 1694 | 'securepoll-unanswered-questions' => 'Debes responder todas las preguntas.', |
| 1695 | + 'securepoll-invalid-rank' => 'Rango inválido. Debes clasificar a los candidatos con un rango entre 1 y 999.', |
| 1696 | + 'securepoll-unranked-options' => 'Algunas opciones no fueron clasificadas. |
| 1697 | +Debes clasificar a todas las opciones con un rango entre 1 y 999.', |
| 1698 | + 'securepoll-remote-auth-error' => 'Se ha producido un error al obtener su información de cuenta del servidor.', |
| 1699 | + 'securepoll-remote-parse-error' => 'Se ha producido un error al interpretar la respuesta de autorización del servidor.', |
1495 | 1700 | 'securepoll-api-invalid-params' => 'Parámetros inválidos.', |
1496 | 1701 | 'securepoll-api-no-user' => 'Ningún usuario fue encontrado con el ID dado.', |
| 1702 | + 'securepoll-api-token-mismatch' => 'Clave de seguridad no coincidente, no se puede iniciar sesión.', |
1497 | 1703 | 'securepoll-not-logged-in' => 'Debes iniciar sesión para votar en esta elección', |
1498 | 1704 | 'securepoll-too-few-edits' => 'Perdón, no puedes votar. Necesitas haber hecho al menos $1 {{PLURAL:$1|edición|ediciones}} para votar en esta elección, has hecho $2.', |
1499 | 1705 | 'securepoll-blocked' => 'Perdón, no puedes votar en esta elección si estás actualmente bloqueado para ediciones.', |
| 1706 | + 'securepoll-bot' => 'Lo sentimos, las cuentas con flag de bot no están autorizadas a votar en esta elección.', |
1500 | 1707 | 'securepoll-not-in-group' => 'Solamente mimbros del grupo $1 pueden votar en esta elección.', |
1501 | 1708 | 'securepoll-not-in-list' => 'Perdón, no estás en el lista predetermindad de usuarios autorizados a votar en esta elección.', |
1502 | 1709 | 'securepoll-list-title' => 'Lista votos: $1', |
— | — | @@ -1507,18 +1714,28 @@ |
1508 | 1715 | 'securepoll-header-strike' => 'Tachar', |
1509 | 1716 | 'securepoll-header-details' => 'Detalles', |
1510 | 1717 | 'securepoll-strike-button' => 'Trachar', |
| 1718 | + 'securepoll-unstrike-button' => 'Validar', |
1511 | 1719 | 'securepoll-strike-reason' => 'Razón:', |
1512 | 1720 | 'securepoll-strike-cancel' => 'Cancelar', |
| 1721 | + 'securepoll-strike-error' => 'Se ha producido un error al invalidar/validar: $1', |
| 1722 | + 'securepoll-strike-token-mismatch' => 'Pérdida de información de la sesión', |
1513 | 1723 | 'securepoll-details-link' => 'Detalles', |
1514 | 1724 | 'securepoll-details-title' => 'Detalles de voto: #$1', |
| 1725 | + 'securepoll-invalid-vote' => '"$1" no es una identidad de voto válida', |
1515 | 1726 | 'securepoll-header-voter-type' => 'Tipo de votante', |
1516 | 1727 | 'securepoll-voter-properties' => 'Propiedades de votante', |
| 1728 | + 'securepoll-strike-log' => 'Registro de votos invalidados', |
1517 | 1729 | 'securepoll-header-action' => 'Acción', |
1518 | 1730 | 'securepoll-header-reason' => 'Razón', |
1519 | 1731 | 'securepoll-header-admin' => 'Administrador', |
| 1732 | + 'securepoll-cookie-dup-list' => 'Usuarios con cookies duplicadas', |
1520 | 1733 | 'securepoll-dump-title' => 'Volcado: $1', |
1521 | 1734 | 'securepoll-dump-no-crypt' => 'No se dispone de un registro encriptado para esta votación dado que esta votación no ha sido configurada para usar encriptación.', |
1522 | 1735 | 'securepoll-dump-not-finished' => 'Los registros encriptados de la votación están únicamente disponibles después de la fecha de finalización en $1 de $2', |
| 1736 | + 'securepoll-dump-no-urandom' => 'Imposible abrir /dev/urandom. |
| 1737 | +Para preservar la privacidad de los votantes, sólo son publicados los resultados encriptados de la elección cuando pueden ser mezclados con un flujo de números aleatorio.', |
| 1738 | + 'securepoll-urandom-not-supported' => 'Este servidor no posee capacidad de generación criptográfica de números aleatorios. |
| 1739 | +Para preservar la privacidad de los votantes, sólo son publicados los resultados encriptados de la elección cuando pueden ser mezclados con un flujo de números aleatorio.', |
1523 | 1740 | 'securepoll-translate-title' => 'Traducir: $1', |
1524 | 1741 | 'securepoll-invalid-language' => 'Código de lenguaje inválido "$1"', |
1525 | 1742 | 'securepoll-submit-translate' => 'Actualizar', |
— | — | @@ -1531,6 +1748,20 @@ |
1532 | 1749 | 'securepoll-subpage-translate' => 'Traducir', |
1533 | 1750 | 'securepoll-subpage-list' => 'Lista', |
1534 | 1751 | 'securepoll-subpage-dump' => 'Volcar', |
| 1752 | + 'securepoll-subpage-tally' => 'Contador', |
| 1753 | + 'securepoll-tally-title' => 'Contador: $1', |
| 1754 | + 'securepoll-tally-not-finished' => 'Lo sentimos, no puede actualizar los contadores de la elección hasta que la votación no haya finalizado.', |
| 1755 | + 'securepoll-can-decrypt' => 'El registro de elección ha sido encriptado pero la clave de desencriptación está disponible. |
| 1756 | +Puede escoger entre escrutar los resultados de la base de datos, o escrutar los resultados encriptados desde un fichero subido.', |
| 1757 | + 'securepoll-tally-no-key' => 'No puede actualizar el contador de la elección, debido a que los votos están encriptados y la clave de desencriptación no está disponible.', |
| 1758 | + 'securepoll-tally-local-legend' => 'Cuenta de resultados actualizada', |
| 1759 | + 'securepoll-tally-local-submit' => 'Crear cuenta', |
| 1760 | + 'securepoll-tally-upload-legend' => 'Subir dump encriptado', |
| 1761 | + 'securepoll-tally-upload-submit' => 'Crear cuenta', |
| 1762 | + 'securepoll-tally-error' => 'Se ha producido un error interpretando el registro de votos, no se puede crear un contador.', |
| 1763 | + 'securepoll-no-upload' => 'No se ha subido ningún fichero, no se pueden contar los resultados.', |
| 1764 | + 'securepoll-dump-corrupt' => 'El archivo volcado se encuentra dañado y no puede ser procesado.', |
| 1765 | + 'securepoll-tally-upload-error' => 'Error al contar el archivo volcado: $1', |
1535 | 1766 | ); |
1536 | 1767 | |
1537 | 1768 | /** Estonian (Eesti) |
— | — | @@ -1574,6 +1805,20 @@ |
1575 | 1806 | 'securepoll-submit-select-lang' => 'Tõlgi', |
1576 | 1807 | ); |
1577 | 1808 | |
| 1809 | +/** Basque (Euskara) |
| 1810 | + * @author An13sa |
| 1811 | + */ |
| 1812 | +$messages['eu'] = array( |
| 1813 | + 'securepoll-header-timestamp' => 'Ordua', |
| 1814 | + 'securepoll-header-voter-name' => 'Izena', |
| 1815 | + 'securepoll-header-reason' => 'Arrazoia', |
| 1816 | + 'securepoll-language-label' => 'Hikuntza aukeratu:', |
| 1817 | + 'securepoll-submit-select-lang' => 'Itzuli', |
| 1818 | + 'securepoll-subpage-vote' => 'Bozkatu', |
| 1819 | + 'securepoll-subpage-translate' => 'Itzuli', |
| 1820 | + 'securepoll-subpage-list' => 'Zerrenda', |
| 1821 | +); |
| 1822 | + |
1578 | 1823 | /** Persian (فارسی) |
1579 | 1824 | * @author Mardetanha |
1580 | 1825 | * @author Meisam |
— | — | @@ -1653,10 +1898,10 @@ |
1654 | 1899 | 'securepoll-no-decryption-key' => 'Salauksen purkuavainta ei ole asetettu. |
1655 | 1900 | Salausta ei voi purkaa.', |
1656 | 1901 | 'securepoll-jump' => 'Siirry äänestyspalvelimelle.', |
1657 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
1658 | | -Äänesi oli epäkelpo: $1 |
1659 | | -</div>', |
| 1902 | + 'securepoll-bad-ballot-submission' => 'Äänesi oli epäkelpo: $1', |
1660 | 1903 | 'securepoll-unanswered-questions' => 'Sinun täytyy vastata kaikkiin kysymyksiin.', |
| 1904 | + 'securepoll-invalid-rank' => 'Virheellinen sijanumero. Ehdokkaille antamasi sijanumeron on sijaittava välillä 1 ja 999.', |
| 1905 | + 'securepoll-unranked-options' => 'Joitain vaihtoehtoja ei asetettu paremmuusjärjestykseen. Jokaiselle vaihtoehdolle pitää tarjota sijoitus väliltä 1 ja 999.', |
1661 | 1906 | 'securepoll-remote-auth-error' => 'Virhe hakiessa käyttäjätilisi tietoja palvelimelta.', |
1662 | 1907 | 'securepoll-remote-parse-error' => 'Virhe tulkittaessa lupavastausta palvelimelta.', |
1663 | 1908 | 'securepoll-api-invalid-params' => 'Virheellisiä parametrejä.', |
— | — | @@ -1681,6 +1926,7 @@ |
1682 | 1927 | 'securepoll-strike-reason' => 'Syy', |
1683 | 1928 | 'securepoll-strike-cancel' => 'Peruuta', |
1684 | 1929 | 'securepoll-strike-error' => 'Tapahtui virhe poistossa/palautuksessa: $1', |
| 1930 | + 'securepoll-strike-token-mismatch' => 'Istuntotiedot hävinneet', |
1685 | 1931 | 'securepoll-details-link' => 'Tiedot', |
1686 | 1932 | 'securepoll-details-title' => 'Äänestystiedot: #$1', |
1687 | 1933 | 'securepoll-invalid-vote' => '"$1" ei ole kelvollinen tunniste.', |
— | — | @@ -1696,6 +1942,7 @@ |
1697 | 1943 | 'securepoll-dump-not-finished' => 'Salauksin suojatut vaalitiedot ovat saatavilla vaalien päättymispäivän jälkeen $1 kello $2', |
1698 | 1944 | 'securepoll-dump-no-urandom' => 'Toimintoa /dev/urandom ei voitu avata. |
1699 | 1945 | Äänestyssalaisuuden varmistamiseksi salatut tietueet ovat julkisesti saatavilla ainoastaan silloin, kun niiden järjestys voidaan sekoittaa turvallisella satunnaislukuvirralla.', |
| 1946 | + 'securepoll-urandom-not-supported' => 'Tämä palvelin ei tue satunnaislukujen tuottoa salauksen alla. Jotta äänestäjien yksityisyys säilytetään, vaalien salauksenalaiset tiedostot ovat julkisesti saatavilla ainoastaan, kun niiden järjestys voidaan sekoittaa turvatusta satunnaislukulähteestä.', |
1700 | 1947 | 'securepoll-translate-title' => 'Käännä: $1', |
1701 | 1948 | 'securepoll-invalid-language' => 'Virheellinen kielikoodi ”$1”', |
1702 | 1949 | 'securepoll-submit-translate' => 'Päivitä', |
— | — | @@ -1720,12 +1967,15 @@ |
1721 | 1968 | 'securepoll-tally-upload-submit' => 'Luo laskenta', |
1722 | 1969 | 'securepoll-tally-error' => 'Virhe äänestystiedoston tulkinnassa, joten ei voitu tuottaa laskentaa.', |
1723 | 1970 | 'securepoll-no-upload' => 'Tiedostoa ei lähetettynä, joten laskenta ei onnistunut.', |
| 1971 | + 'securepoll-dump-corrupt' => 'Vedostiedosto on vioittunut eikä sitä voida käsitellä.', |
| 1972 | + 'securepoll-tally-upload-error' => 'Virhe vedostiedoston tarkistamisessa: $1', |
1724 | 1973 | ); |
1725 | 1974 | |
1726 | 1975 | /** French (Français) |
1727 | 1976 | * @author Crochet.david |
1728 | 1977 | * @author IAlex |
1729 | 1978 | * @author Louperivois |
| 1979 | + * @author Omnipaedista |
1730 | 1980 | * @author PieRRoMaN |
1731 | 1981 | */ |
1732 | 1982 | $messages['fr'] = array( |
— | — | @@ -1773,6 +2023,9 @@ |
1774 | 2024 | 'securepoll-jump' => 'Aller au serveur de vote', |
1775 | 2025 | 'securepoll-bad-ballot-submission' => 'Votre vote est invalide : $1', |
1776 | 2026 | 'securepoll-unanswered-questions' => 'Vous devez répondre à toutes les questions.', |
| 2027 | + 'securepoll-invalid-rank' => 'Rang invalide. Vous devez donner aux candidats un rang entre 1 et 999.', |
| 2028 | + 'securepoll-unranked-options' => "Certaines options n'ont pas reçu de rang. |
| 2029 | +Vous devez donner un rang entre 1 et 999 à toutes les options.", |
1777 | 2030 | 'securepoll-remote-auth-error' => 'Erreur lors de la récupération des informations de votre compte depuis le serveur.', |
1778 | 2031 | 'securepoll-remote-parse-error' => 'Erreur lors de l’interprétation de la réponse d’autorisation du serveur.', |
1779 | 2032 | 'securepoll-api-invalid-params' => 'Parmamètres invalides.', |
— | — | @@ -1797,6 +2050,7 @@ |
1798 | 2051 | 'securepoll-strike-reason' => 'Raison :', |
1799 | 2052 | 'securepoll-strike-cancel' => 'Annuler', |
1800 | 2053 | 'securepoll-strike-error' => 'Erreur lors du (dé)biffage : $1', |
| 2054 | + 'securepoll-strike-token-mismatch' => 'Perte des données de session', |
1801 | 2055 | 'securepoll-details-link' => 'Détails', |
1802 | 2056 | 'securepoll-details-title' => 'Détails du vote : #$1', |
1803 | 2057 | 'securepoll-invalid-vote' => '« $1 » n’est pas un ID de vote valide', |
— | — | @@ -1812,6 +2066,8 @@ |
1813 | 2067 | 'securepoll-dump-not-finished' => 'Les données cryptées ne sont disponibles qu’après la clôture de l’élection le $1 à $2', |
1814 | 2068 | 'securepoll-dump-no-urandom' => 'Impossible d’ouvrir /dev/urandom. |
1815 | 2069 | Pour maintenir la confidentialité des votants, les données cryptées ne sont disponibles que si elles peuvent être brouillées avec un nombre de caractères aléatoires.', |
| 2070 | + 'securepoll-urandom-not-supported' => 'Ce serveur ne supporte pas la génération cryptographique aléatoire de nombres. |
| 2071 | +Pour assurer la confidentialité des votants, les données cryptées ne sont publiés uniquement quand ils peuvent être brouillés avec un flux de nombres aléatoires.', |
1816 | 2072 | 'securepoll-translate-title' => 'Traduire : $1', |
1817 | 2073 | 'securepoll-invalid-language' => 'Code de langue « $1 » invalide.', |
1818 | 2074 | 'securepoll-submit-translate' => 'Mettre à jour', |
— | — | @@ -1836,6 +2092,8 @@ |
1837 | 2093 | 'securepoll-tally-upload-submit' => 'Créer une comptage', |
1838 | 2094 | 'securepoll-tally-error' => 'Erreur lors de l’interprétation des enregistrements de vote, impossible de produire un résultat.', |
1839 | 2095 | 'securepoll-no-upload' => 'Aucun fichier n’a été téléchargé, impossible de compter les résultats.', |
| 2096 | + 'securepoll-dump-corrupt' => 'Le fichier de sauvegarde est corrompu et ne peut pas être utilisé.', |
| 2097 | + 'securepoll-tally-upload-error' => 'Erreur lors du dépouillement du fichier de sauvegarde : $1', |
1840 | 2098 | ); |
1841 | 2099 | |
1842 | 2100 | /** Irish (Gaeilge) |
— | — | @@ -1898,6 +2156,9 @@ |
1899 | 2157 | 'securepoll-jump' => 'Ir ao servidor de votos', |
1900 | 2158 | 'securepoll-bad-ballot-submission' => 'O seu voto foi inválido: $1', |
1901 | 2159 | 'securepoll-unanswered-questions' => 'Debe responder a todas as preguntas.', |
| 2160 | + 'securepoll-invalid-rank' => 'Clasificación inválida. Debe darlles aos candidatos unha clasificación que estea entre 1 e 999.', |
| 2161 | + 'securepoll-unranked-options' => 'Algunhas opcións non foron clasificadas. |
| 2162 | +Debe darlles a todas as opcións unha clasificación que estea entre 1 e 999.', |
1902 | 2163 | 'securepoll-remote-auth-error' => 'Erro ao enviar a información da túa conta desde o servidor.', |
1903 | 2164 | 'securepoll-remote-parse-error' => 'Erro ao interpretar a autorización de resposta desde o servidor.', |
1904 | 2165 | 'securepoll-api-invalid-params' => 'Parámetros inválidos.', |
— | — | @@ -1922,6 +2183,7 @@ |
1923 | 2184 | 'securepoll-strike-reason' => 'Motivo:', |
1924 | 2185 | 'securepoll-strike-cancel' => 'Cancelar', |
1925 | 2186 | 'securepoll-strike-error' => 'Erro ao levar a cabo o risco/a retirada do risco: $1', |
| 2187 | + 'securepoll-strike-token-mismatch' => 'Perdéronse os datos da sesión', |
1926 | 2188 | 'securepoll-details-link' => 'Detalles', |
1927 | 2189 | 'securepoll-details-title' => 'Detalles do voto: #$1', |
1928 | 2190 | 'securepoll-invalid-vote' => '"$1" non é un ID de voto válido', |
— | — | @@ -1937,6 +2199,8 @@ |
1938 | 2200 | 'securepoll-dump-not-finished' => 'Os rexistros das eleccións encriptados só están dispoñibles despois da data de fin o $1 ás $2', |
1939 | 2201 | 'securepoll-dump-no-urandom' => 'Non se pode abrir /dev/urandom. |
1940 | 2202 | Para manter a protección dos datos, os rexistros das eleccións encriptados só están dispoñibles publicamente cando poden ser baraxados cunha secuencia de números aleatorios.', |
| 2203 | + 'securepoll-urandom-not-supported' => 'Este servidor non soporta a xeración criptográfica de números aleatorios. |
| 2204 | +Para manter a confidencialidade dos votantes, os rexistros cifrados das eleccións só están dispoñibles publicamente cando se poden barallar cun fluxo de números aleatorios.', |
1941 | 2205 | 'securepoll-translate-title' => 'Traducir: $1', |
1942 | 2206 | 'securepoll-invalid-language' => 'Código de lingua inválido "$1"', |
1943 | 2207 | 'securepoll-submit-translate' => 'Actualizar', |
— | — | @@ -1961,8 +2225,31 @@ |
1962 | 2226 | 'securepoll-tally-upload-submit' => 'Crear o escrutinio', |
1963 | 2227 | 'securepoll-tally-error' => 'Erro de interpretación no rexistro da votación, non se pode producir un escrutinio.', |
1964 | 2228 | 'securepoll-no-upload' => 'Non foi cargado ningún ficheiro, non se poden escrutar os resultados.', |
| 2229 | + 'securepoll-dump-corrupt' => 'O ficheiro de descarga está danado e non pode ser procesado.', |
| 2230 | + 'securepoll-tally-upload-error' => 'Erro ao enumerar o ficheiro de descarga: $1', |
1965 | 2231 | ); |
1966 | 2232 | |
| 2233 | +/** Ancient Greek (Ἀρχαία ἑλληνικὴ) |
| 2234 | + * @author Crazymadlover |
| 2235 | + * @author Omnipaedista |
| 2236 | + */ |
| 2237 | +$messages['grc'] = array( |
| 2238 | + 'securepoll-header-timestamp' => 'Χρόνος', |
| 2239 | + 'securepoll-header-voter-name' => 'Ὄνομα', |
| 2240 | + 'securepoll-header-voter-domain' => 'Περιοχή', |
| 2241 | + 'securepoll-strike-reason' => 'Αἰτία:', |
| 2242 | + 'securepoll-strike-cancel' => 'Ἀκυροῦν', |
| 2243 | + 'securepoll-details-link' => 'Λεπτομέρειαι', |
| 2244 | + 'securepoll-header-action' => 'Δρᾶσις', |
| 2245 | + 'securepoll-header-reason' => 'Αἰτία', |
| 2246 | + 'securepoll-language-label' => 'Ἐπιλέγειν γλῶτταν:', |
| 2247 | + 'securepoll-submit-select-lang' => 'Μεταγλωττίζειν', |
| 2248 | + 'securepoll-header-title' => 'Ὄνομα', |
| 2249 | + 'securepoll-subpage-vote' => 'Ψηφίζειν', |
| 2250 | + 'securepoll-subpage-tally' => 'Ψηφομέτρησις', |
| 2251 | + 'securepoll-tally-title' => 'Ψηφομέτρησις: $1', |
| 2252 | +); |
| 2253 | + |
1967 | 2254 | /** Swiss German (Alemannisch) |
1968 | 2255 | * @author Als-Holder |
1969 | 2256 | */ |
— | — | @@ -2011,6 +2298,9 @@ |
2012 | 2299 | 'securepoll-jump' => 'Gang zum Stimm-Server', |
2013 | 2300 | 'securepoll-bad-ballot-submission' => 'Dyy Stimm isch nit giltig: $1', |
2014 | 2301 | 'securepoll-unanswered-questions' => 'Du muesch uf alli Froge Antwort gee.', |
| 2302 | + 'securepoll-invalid-rank' => 'Nit giltigi Rangfolg. Du muesch dr Kandidate e Rangnummere zwische 1 un 999 gee.', |
| 2303 | + 'securepoll-unranked-options' => 'E Teil Optione hän kei Rangnummere. |
| 2304 | +Du muesch allene Optione e Rangnummere zwische 1 un 999 gee.', |
2015 | 2305 | 'securepoll-remote-auth-error' => 'Fähler bim Abruefe vu Dyyne Benutzerkontoinformatione vum Server.', |
2016 | 2306 | 'securepoll-remote-parse-error' => 'Fähler bim Dyte vu dr Autorisierigsantwort vum Server', |
2017 | 2307 | 'securepoll-api-invalid-params' => 'Nit giltigi Parameter.', |
— | — | @@ -2035,6 +2325,7 @@ |
2036 | 2326 | 'securepoll-strike-reason' => 'Grund:', |
2037 | 2327 | 'securepoll-strike-cancel' => 'Abbräche', |
2038 | 2328 | 'securepoll-strike-error' => 'Fähler bi dr Strychig/Strychigsrucknahm: $1', |
| 2329 | + 'securepoll-strike-token-mismatch' => 'Sitzígsdate verlore', |
2039 | 2330 | 'securepoll-details-link' => 'Detail', |
2040 | 2331 | 'securepoll-details-title' => 'Abstimmigsdetail: #$1', |
2041 | 2332 | 'securepoll-invalid-vote' => '„$1“ isch kei giltigi Abstimmigs-ID', |
— | — | @@ -2050,6 +2341,8 @@ |
2051 | 2342 | 'securepoll-dump-not-finished' => 'Verschlissleti Abstimmigsufzeichnige sin nume noch em Ändtermin am $1 am $2 verfiegbar', |
2052 | 2343 | 'securepoll-dump-no-urandom' => '/dev/urandom cha nit ufgmacht wäre. |
2053 | 2344 | Go dr Wehlerdateschutz wohre, sin verschlissleti Abstimmigsufzeichnige nume effentli verfiebar, wänn si mit eme sichere Zuefallszahlestrom chenne gmischt wäre.', |
| 2345 | + 'securepoll-urandom-not-supported' => 'Dää Server unterstitzt kei kryptografischi Zuefallszahlegenerierig. |
| 2346 | +Ass es Wahlgheimnis sicher gstellt isch, sin verschlssleti Wahlufzeichnige nume effetlig verfiegbar, wänn si mit ere sichere Zuefallszahlereihefolg chenne vermischt wäre.', |
2054 | 2347 | 'securepoll-translate-title' => 'Ibersetze: $1', |
2055 | 2348 | 'securepoll-invalid-language' => 'Nit giltige Sprochcode „$1“', |
2056 | 2349 | 'securepoll-submit-translate' => 'Aktualisiere', |
— | — | @@ -2074,10 +2367,13 @@ |
2075 | 2368 | 'securepoll-tally-upload-submit' => 'Uuszellig aalege', |
2076 | 2369 | 'securepoll-tally-error' => 'Fähler bim Interpretiere vu dr Abstimmigsufzeichnig, Uuszellig cha nit aagleit wäre.', |
2077 | 2370 | 'securepoll-no-upload' => 'S isch kei Datei ufeglade wore, cha d Ergebnis nit uuszelle.', |
| 2371 | + 'securepoll-dump-corrupt' => 'D Uusgabe-Datei isch fählerhaft un cha nit verarbeitet wäre.', |
| 2372 | + 'securepoll-tally-upload-error' => 'Fähler in dr gwichtete Uusgabe-Datei: $1', |
2078 | 2373 | ); |
2079 | 2374 | |
2080 | 2375 | /** Hebrew (עברית) |
2081 | 2376 | * @author Rotem Liss |
| 2377 | + * @author Rotemliss |
2082 | 2378 | * @author דניאל ב. |
2083 | 2379 | */ |
2084 | 2380 | $messages['he'] = array( |
— | — | @@ -2125,6 +2421,9 @@ |
2126 | 2422 | 'securepoll-jump' => 'מעבר לשרת ההצבעה', |
2127 | 2423 | 'securepoll-bad-ballot-submission' => 'הצבעתכם הייתה בלתי תקינה: $1', |
2128 | 2424 | 'securepoll-unanswered-questions' => 'עליכם לענות על כל השאלות.', |
| 2425 | + 'securepoll-invalid-rank' => 'הדירוג אינו תקין. יש לתת למועמדים דירוג בין 1 ל־999.', |
| 2426 | + 'securepoll-unranked-options' => 'כמה מהאפשרויות לא דורגו. |
| 2427 | +יש לקבוע לכל האפשרויות דירוג בין 1 ל־999.', |
2129 | 2428 | 'securepoll-remote-auth-error' => 'שגיאה בקבלת פרטי החשבון שלכם מהשרת.', |
2130 | 2429 | 'securepoll-remote-parse-error' => 'שגיאה בפענוח התגובה על מידע הכניסה מהשרת.', |
2131 | 2430 | 'securepoll-api-invalid-params' => 'פרמטרים בלתי תקינים.', |
— | — | @@ -2149,6 +2448,7 @@ |
2150 | 2449 | 'securepoll-strike-reason' => 'סיבה:', |
2151 | 2450 | 'securepoll-strike-cancel' => 'ביטול', |
2152 | 2451 | 'securepoll-strike-error' => 'שגיאה בביצוע הסתרה או בביטול הסתרה: $1', |
| 2452 | + 'securepoll-strike-token-mismatch' => 'מידע הכניסה אבד', |
2153 | 2453 | 'securepoll-details-link' => 'פרטים', |
2154 | 2454 | 'securepoll-details-title' => 'פרטי ההצבעה: #$1', |
2155 | 2455 | 'securepoll-invalid-vote' => '"$1" אינו מספר הצבעה תקין', |
— | — | @@ -2165,6 +2465,8 @@ |
2166 | 2466 | 'securepoll-dump-not-finished' => 'רשומות ההצבעה המוצפנות זמינות רק לאחר תאריך הסיום ב־$2, $1', |
2167 | 2467 | 'securepoll-dump-no-urandom' => 'לא ניתן לפתוח את /dev/urandom. |
2168 | 2468 | כדי לשמור על פרטיות המצביעים, רשומות ההצבעה המוצפנות זמינותת באופן ציבורי רק כאשר ניתן לערבב אותן באמצעות זרם המשתמש במספר אקראי מאובטח.', |
| 2469 | + 'securepoll-urandom-not-supported' => 'שרת זה אינו תומך ביצירת מספרים אקראיים לצורך הצפנה. |
| 2470 | +כדי לשמור על פרטיות הבוחרים, רשומות ההצבעה המוצפנות תהיינה זמינות לציבור רק כאשר ניתן יהיה לערבלן באמצעות זרם מספרים אקראיים מאובטח.', |
2169 | 2471 | 'securepoll-translate-title' => 'תרגום: $1', |
2170 | 2472 | 'securepoll-invalid-language' => 'קוד שפה בלתי תקין "$1"', |
2171 | 2473 | 'securepoll-header-trans-id' => 'מספר', |
— | — | @@ -2192,6 +2494,120 @@ |
2193 | 2495 | 'securepoll-no-upload' => 'לא הועלה קובץ, לא ניתן לחשב את התוצאות.', |
2194 | 2496 | ); |
2195 | 2497 | |
| 2498 | +/** Croatian (Hrvatski) |
| 2499 | + * @author SpeedyGonsales |
| 2500 | + * @author Suradnik13 |
| 2501 | + */ |
| 2502 | +$messages['hr'] = array( |
| 2503 | + 'securepoll' => 'SigurnoGlasovanje', |
| 2504 | + 'securepoll-desc' => 'Mediawiki ekstenzija za izbore i ankete', |
| 2505 | + 'securepoll-invalid-page' => 'Nevaljana podstranica "<nowiki>$1</nowiki>"', |
| 2506 | + 'securepoll-need-admin' => 'Morate biti administrator za izvršenje ove radnje.', |
| 2507 | + 'securepoll-too-few-params' => 'Nema dovoljno parametara podstranice (neispravna poveznica).', |
| 2508 | + 'securepoll-invalid-election' => '"$1" nije valjani izborni ID.', |
| 2509 | + 'securepoll-welcome' => '<strong>Dobrodošli $1!</strong>', |
| 2510 | + 'securepoll-not-started' => 'Izbori nisu još počeli. |
| 2511 | +Počinju dana $2 u $3 sati.', |
| 2512 | + 'securepoll-finished' => 'Ovi izbori su okončani, ne možete više glasovati.', |
| 2513 | + 'securepoll-not-qualified' => 'Niste kvalificirani za glasovanje na ovim izborima: $1', |
| 2514 | + 'securepoll-change-disallowed' => 'Već ste glasovali na ovim izborima. |
| 2515 | +Žalimo, ne možete glasovati opet.', |
| 2516 | + 'securepoll-change-allowed' => '<strong>Napomena: Vi ste već glasovali na ovim izborima.</strong> |
| 2517 | +Možete promijeniti svoj glas/svoje glasove ispunjavanjem donjeg obrasca. |
| 2518 | +No ako to učinite, vaše će prvo glasovanje biti poništeno.', |
| 2519 | + 'securepoll-submit' => 'Pošalji (glasuj)', |
| 2520 | + 'securepoll-gpg-receipt' => 'Hvala vam na glasovanju. |
| 2521 | + |
| 2522 | +Ako želite, možete zadržati (snimiti) slijedeći izraz kao dokaz vašeg glasovanja: |
| 2523 | + |
| 2524 | +<pre>$1</pre>', |
| 2525 | + 'securepoll-thanks' => 'Hvala, Vaš glas je zaprimljen.', |
| 2526 | + 'securepoll-return' => 'Vrati se na $1', |
| 2527 | + 'securepoll-encrypt-error' => 'Neuspjela enkripcija vašeg glasa. |
| 2528 | +Vaš glas nije zabilježen! |
| 2529 | + |
| 2530 | +$1', |
| 2531 | + 'securepoll-no-gpg-home' => "Nije moguće napraviti GPG ''home'' direktorij.", |
| 2532 | + 'securepoll-secret-gpg-error' => 'Greška pri izvršavanju GPG-a. |
| 2533 | +Postavite $wgSecurePollShowErrorDetail=true; u LocalSettings.php datoteci da bi vidjeli više detalja.', |
| 2534 | + 'securepoll-full-gpg-error' => 'Pogreška pri izvršavanju GPG-a: |
| 2535 | + |
| 2536 | +Naredba: $1 |
| 2537 | + |
| 2538 | +Pogreška: |
| 2539 | +<pre>$2</pre>', |
| 2540 | + 'securepoll-gpg-config-error' => 'GPG ključevi nisu pravilno konfigurirani.', |
| 2541 | + 'securepoll-gpg-parse-error' => 'Pogreška pri prijevodu izlaza iz GPG-a.', |
| 2542 | + 'securepoll-no-decryption-key' => 'Dekripcijski ključ nije konfiguriran. |
| 2543 | +Dekripcija nije moguća.', |
| 2544 | + 'securepoll-jump' => 'Idi na poslužitelj za glasovanje', |
| 2545 | + 'securepoll-bad-ballot-submission' => 'Vaš glas je bio nevažeći: $1', |
| 2546 | + 'securepoll-unanswered-questions' => 'Morate odgovoriti na sva pitanja.', |
| 2547 | + 'securepoll-remote-auth-error' => 'Pogreška pri dobavljanje informacije o Vašem računu s poslužitelja.', |
| 2548 | + 'securepoll-remote-parse-error' => 'Pogreška pri tumačenju autorizacijskog odgovora s poslužitelja.', |
| 2549 | + 'securepoll-api-invalid-params' => 'Nevažeći parametri.', |
| 2550 | + 'securepoll-api-no-user' => 'Nema suradnika s tim ID brojem.', |
| 2551 | + 'securepoll-api-token-mismatch' => 'Neslaganje sigurnosnog tokena, neuspjela prijava.', |
| 2552 | + 'securepoll-not-logged-in' => 'Morate se prijaviti da bi mogli glasovati na ovim izborima', |
| 2553 | + 'securepoll-too-few-edits' => 'Nažalost, ne možete glasovati. Morate imati najmanje $1 {{PLURAL:$1|uređivanje|uređivanja|uređivanja}} da bi mogli glasovati na ovim izborima, vi ih imate $2.', |
| 2554 | + 'securepoll-blocked' => 'Nažalost, ne možete glasovati na ovim izborima ako ste trenutačno blokirani', |
| 2555 | + 'securepoll-bot' => 'Nažalost, računi s bot statusom ne mogu glasovati na ovim izborima.', |
| 2556 | + 'securepoll-not-in-group' => 'Samo članovi "$1" grupe mogu glasovati na ovim izborima.', |
| 2557 | + 'securepoll-not-in-list' => 'Nažalost, niste na popisu ovlaštenih suradnika koji mogu glasovati na ovim izborima.', |
| 2558 | + 'securepoll-list-title' => 'Popis glasova: $1', |
| 2559 | + 'securepoll-header-timestamp' => 'Vrijeme', |
| 2560 | + 'securepoll-header-voter-name' => 'Ime', |
| 2561 | + 'securepoll-header-voter-domain' => 'Domena', |
| 2562 | + 'securepoll-header-ua' => 'Suradnički posrednik', |
| 2563 | + 'securepoll-header-cookie-dup' => 'Dupl', |
| 2564 | + 'securepoll-header-strike' => 'Prekriži', |
| 2565 | + 'securepoll-header-details' => 'Detalji', |
| 2566 | + 'securepoll-strike-button' => 'Prekriži', |
| 2567 | + 'securepoll-unstrike-button' => 'Ukloni prekriženo', |
| 2568 | + 'securepoll-strike-reason' => 'Razlog:', |
| 2569 | + 'securepoll-strike-cancel' => 'Odustani', |
| 2570 | + 'securepoll-strike-error' => 'Pogreška tijekom izvođenja prekriži/ukloni prekriženo: $1', |
| 2571 | + 'securepoll-details-link' => 'Detalji', |
| 2572 | + 'securepoll-details-title' => 'Detalji glasovanja: #$1', |
| 2573 | + 'securepoll-invalid-vote' => '"$1" nije valjan glasački ID', |
| 2574 | + 'securepoll-header-voter-type' => 'Vrsta glasača', |
| 2575 | + 'securepoll-voter-properties' => 'Svojstva glasača', |
| 2576 | + 'securepoll-strike-log' => 'Evidencija križanja', |
| 2577 | + 'securepoll-header-action' => 'Radnja', |
| 2578 | + 'securepoll-header-reason' => 'Razlog', |
| 2579 | + 'securepoll-header-admin' => 'Admin', |
| 2580 | + 'securepoll-cookie-dup-list' => 'Suradnici s dvostrukim kolačićima', |
| 2581 | + 'securepoll-dump-title' => 'Ispis: $1', |
| 2582 | + 'securepoll-dump-no-crypt' => 'Enkriptirani zapis ovih izbora nije dostupan, jer enkripcija nije postavljena.', |
| 2583 | + 'securepoll-dump-not-finished' => 'Enkriptirani zapisi izbora dostupni su samo poslije datuma okončanja - $1 u $2 sati', |
| 2584 | + 'securepoll-dump-no-urandom' => 'Ne mogu otvoriti /dev/urandom. |
| 2585 | +Da biste zadržali privatnost glasača, enkriptirani zapisi izbora su javno dostupni samo kad ih se može izmiješati uporabom niza sigurnih slučajnih brojeva.', |
| 2586 | + 'securepoll-translate-title' => 'Prevedi: $1', |
| 2587 | + 'securepoll-invalid-language' => 'Neispravan jezični kôd "$1"', |
| 2588 | + 'securepoll-submit-translate' => 'Ažuriraj', |
| 2589 | + 'securepoll-language-label' => 'Odaberite jezik:', |
| 2590 | + 'securepoll-submit-select-lang' => 'Prevedi', |
| 2591 | + 'securepoll-header-title' => 'Ime', |
| 2592 | + 'securepoll-header-start-date' => 'Početni datum', |
| 2593 | + 'securepoll-header-end-date' => 'Krajnji datum', |
| 2594 | + 'securepoll-subpage-vote' => 'Glasaj', |
| 2595 | + 'securepoll-subpage-translate' => 'Prevedi', |
| 2596 | + 'securepoll-subpage-list' => 'Popis', |
| 2597 | + 'securepoll-subpage-dump' => 'Ispis', |
| 2598 | + 'securepoll-subpage-tally' => 'Rezultat', |
| 2599 | + 'securepoll-tally-title' => 'Rezultat: $1', |
| 2600 | + 'securepoll-tally-not-finished' => 'Nažalost, ne možete vidjeti rezultate izbora za trajanja glasovanja.', |
| 2601 | + 'securepoll-can-decrypt' => 'Izborni zapis je enkriptiran, ali dekripcijski ključ je dostupan. |
| 2602 | +Možete odabrati bilo prikaz rezultata iz baze podataka, ili prikaz enkriptiranih rezultata iz učitane datoteke.', |
| 2603 | + 'securepoll-tally-no-key' => 'Ne možete prikazati rezultate ovih izbore, jer su glasovi enkriptirani a dekripcijski ključ nije dostupan.', |
| 2604 | + 'securepoll-tally-local-legend' => 'Prikaži raspodjelu glasova pohranjenih izbora', |
| 2605 | + 'securepoll-tally-local-submit' => 'Napravi prikaz rezultata', |
| 2606 | + 'securepoll-tally-upload-legend' => 'Učitaj enkriptirani ispis', |
| 2607 | + 'securepoll-tally-upload-submit' => 'Napravi prikaz rezultata (raspodjelu glasova)', |
| 2608 | + 'securepoll-tally-error' => 'Pogreška pri prijevodu zapisa glasa, nije moguće prikazati raspodjelu glasova.', |
| 2609 | + 'securepoll-no-upload' => 'Datoteka nije učitana, ne mogu prikazati raspodjelu rezultata.', |
| 2610 | +); |
| 2611 | + |
2196 | 2612 | /** Upper Sorbian (Hornjoserbsce) |
2197 | 2613 | * @author Michawiki |
2198 | 2614 | */ |
— | — | @@ -2240,6 +2656,9 @@ |
2241 | 2657 | 'securepoll-jump' => 'K serwerej wothłosowanja', |
2242 | 2658 | 'securepoll-bad-ballot-submission' => 'Twój hłós bě njepłaćiwy: $1', |
2243 | 2659 | 'securepoll-unanswered-questions' => 'Dyrbiš na wšě prašenja wotmołwić.', |
| 2660 | + 'securepoll-invalid-rank' => 'Njepłaćiwy rjad. Dyrbiš kandidatam rjad mjez 1 a 999 dać.', |
| 2661 | + 'securepoll-unranked-options' => 'Někotre opcije rjad nimaja. |
| 2662 | +Dyrbiš wšěm opcijam rjad mjez 1 a 999 dać.', |
2244 | 2663 | 'securepoll-remote-auth-error' => 'Zmylk při wotwołowanju kontowych informacijow ze serwera.', |
2245 | 2664 | 'securepoll-remote-parse-error' => 'Zmylk při interpretowanju awtorizaciskeje wotmołwy serwera.', |
2246 | 2665 | 'securepoll-api-invalid-params' => 'Njepłaćiwe parametry.', |
— | — | @@ -2264,6 +2683,7 @@ |
2265 | 2684 | 'securepoll-strike-reason' => 'Přičina:', |
2266 | 2685 | 'securepoll-strike-cancel' => 'Přetorhnyć', |
2267 | 2686 | 'securepoll-strike-error' => 'Zmylk při přewjedźenju šmórnjenja/cofnjenja šmórnjenja: $1', |
| 2687 | + 'securepoll-strike-token-mismatch' => 'Daty posedźenja zhubjene', |
2268 | 2688 | 'securepoll-details-link' => 'Podrobnosće', |
2269 | 2689 | 'securepoll-details-title' => 'Podrobnosće hłosowanja: #$1', |
2270 | 2690 | 'securepoll-invalid-vote' => '"$1" płaćiwy hłosowanski ID njeje.', |
— | — | @@ -2279,6 +2699,8 @@ |
2280 | 2700 | 'securepoll-dump-not-finished' => 'Zaklučowane zapiski wólby jenož po kónčnym datumje $1 $2 k dispoziciji steja', |
2281 | 2701 | 'securepoll-dump-no-urandom' => '/dev/urandom njeda so wočinić. |
2282 | 2702 | Zo by so škit datow wolerja wobchował, zaklučowane zapisy jenož zjawnje k dispoziciji steja, hdyž hodźa so z wěstotnym prudom připadnych ličbow měšeć.', |
| 2703 | + 'securepoll-urandom-not-supported' => 'Tutón serwer kryptografiske płodźenje připadnych ličbow njepodpěruje. |
| 2704 | +Zo by so priwatnosć wolerja wobchowała, su zaklučowane wólbne zapiski jenož zjawnje k dispoziciji, hdyž dadźa so z wěstym prudom připadnych ličbow měšeć.', |
2283 | 2705 | 'securepoll-translate-title' => 'Přełožić: $1', |
2284 | 2706 | 'securepoll-invalid-language' => 'Njepłaćiwy rěčny kod "$1"', |
2285 | 2707 | 'securepoll-submit-translate' => 'Aktualizować', |
— | — | @@ -2303,10 +2725,14 @@ |
2304 | 2726 | 'securepoll-tally-upload-submit' => 'Ličenje wutworić', |
2305 | 2727 | 'securepoll-tally-error' => 'Zmylk při interpretowanju zapisow wothłosowanja, ličenje njeda so wutworić.', |
2306 | 2728 | 'securepoll-no-upload' => 'Njeje so žana dataja nahrała, wuslědki njehodźa so ličić.', |
| 2729 | + 'securepoll-dump-corrupt' => 'Dataja składowakoweho wobsaha je poškodźeny a njeda so předźěłać.', |
| 2730 | + 'securepoll-tally-upload-error' => 'Zmylk při wuličowanju dataje składowakeho wobsaha: $1', |
2307 | 2731 | ); |
2308 | 2732 | |
2309 | 2733 | /** Hungarian (Magyar) |
2310 | 2734 | * @author Bdamokos |
| 2735 | + * @author Cassandro |
| 2736 | + * @author Cbrown1023 |
2311 | 2737 | * @author Dani |
2312 | 2738 | * @author Tgr |
2313 | 2739 | */ |
— | — | @@ -2353,10 +2779,11 @@ |
2354 | 2780 | 'securepoll-no-decryption-key' => 'Nincs visszafejtő kulcs beállítva. |
2355 | 2781 | Nem lehet visszafejteni.', |
2356 | 2782 | 'securepoll-jump' => 'Irány a szavazás-szerverre', |
2357 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
2358 | | -A szavazatod érvénytelen volt: $1 |
2359 | | -</div>', |
| 2783 | + 'securepoll-bad-ballot-submission' => 'A szavazatod érvénytelen volt: $1', |
2360 | 2784 | 'securepoll-unanswered-questions' => 'Minden kérdésre válaszolnod kell.', |
| 2785 | + 'securepoll-invalid-rank' => 'Érvénytelen helyezés. A jelölteknek csak 1 és 999 közötti helyezést adhatsz.', |
| 2786 | + 'securepoll-unranked-options' => 'Néhány javaslatra nem adtál helyezést. |
| 2787 | +Minden javaslathoz egy 1 és 999 közötti helyezést kell adnod.', |
2361 | 2788 | 'securepoll-remote-auth-error' => 'Nem sikerült lekérdezni a felhasználói fiókod adatait a szerverről.', |
2362 | 2789 | 'securepoll-remote-parse-error' => 'Nem sikerült értelmezni a szerver autorizációs válaszát.', |
2363 | 2790 | 'securepoll-api-invalid-params' => 'Érvénytelen paraméterek.', |
— | — | @@ -2372,6 +2799,8 @@ |
2373 | 2800 | 'securepoll-header-timestamp' => 'Idő', |
2374 | 2801 | 'securepoll-header-voter-name' => 'Név', |
2375 | 2802 | 'securepoll-header-voter-domain' => 'Domain', |
| 2803 | + 'securepoll-header-ua' => 'Böngésző', |
| 2804 | + 'securepoll-header-cookie-dup' => 'Duplikátum', |
2376 | 2805 | 'securepoll-header-strike' => 'Törlés', |
2377 | 2806 | 'securepoll-header-details' => 'Részletek', |
2378 | 2807 | 'securepoll-strike-button' => 'Törlés', |
— | — | @@ -2379,6 +2808,7 @@ |
2380 | 2809 | 'securepoll-strike-reason' => 'Ok:', |
2381 | 2810 | 'securepoll-strike-cancel' => 'Mégse', |
2382 | 2811 | 'securepoll-strike-error' => 'Hiba történt a törléskor vagy a törlés visszavonásakor: $1', |
| 2812 | + 'securepoll-strike-token-mismatch' => 'A munkafázis adatai elvesztek.', |
2383 | 2813 | 'securepoll-details-link' => 'Részletek', |
2384 | 2814 | 'securepoll-details-title' => 'A szavazás részletei: #$1', |
2385 | 2815 | 'securepoll-invalid-vote' => 'A(z) „$1” nem érvényes szavazatazonosító', |
— | — | @@ -2388,16 +2818,40 @@ |
2389 | 2819 | 'securepoll-header-action' => 'Művelet', |
2390 | 2820 | 'securepoll-header-reason' => 'Ok', |
2391 | 2821 | 'securepoll-header-admin' => 'Adminisztrátor', |
| 2822 | + 'securepoll-cookie-dup-list' => 'Többször szavazók (süti alapján)', |
2392 | 2823 | 'securepoll-dump-title' => 'Dump: $1', |
2393 | 2824 | 'securepoll-dump-no-crypt' => 'A szavazáshoz nem érhető el titkosított szavazatjegyzőkönyv, mert nem lett hozzá titkosítás beállítva.', |
2394 | 2825 | 'securepoll-dump-not-finished' => 'A titkosított szavazatjegyzőkönyvek csak a befejezési dátum ($1 $2) után érhetőek el.', |
2395 | 2826 | 'securepoll-dump-no-urandom' => 'Nem nyitható meg a /dev/urandom. |
2396 | 2827 | A szavazók névtelenségének megőrzése érdekében a titkosított szavazójegyzőkönyv csak akkor érhető el nyilvánosan, ha egy biztonságos véletlenszám-sorozattal lehet keverni.', |
| 2828 | + 'securepoll-urandom-not-supported' => 'Ez a szerver nem képes titkosításra alkalmas véletlenszámokat generálni. |
| 2829 | +A szavazás titkosságának megőrzésére a titkosított szavazatok csak akkor válnak nyilvánossá, ha rendelkezésre áll olyan egy biztonságos véletlenszámforrás, amivel a sorrendjük megkeverhető.', |
2397 | 2830 | 'securepoll-translate-title' => 'Fordítás: $1', |
2398 | 2831 | 'securepoll-invalid-language' => 'Érvénytelen nyelvkód: „$1”', |
2399 | 2832 | 'securepoll-submit-translate' => 'Frissítés', |
2400 | 2833 | 'securepoll-language-label' => 'Nyelv kiválasztása:', |
2401 | 2834 | 'securepoll-submit-select-lang' => 'Fordítás', |
| 2835 | + 'securepoll-header-title' => 'Név', |
| 2836 | + 'securepoll-header-start-date' => 'Kezdődátum', |
| 2837 | + 'securepoll-header-end-date' => 'Záródátum', |
| 2838 | + 'securepoll-subpage-vote' => 'Szavazás', |
| 2839 | + 'securepoll-subpage-translate' => 'Fordítás', |
| 2840 | + 'securepoll-subpage-list' => 'Listázás', |
| 2841 | + 'securepoll-subpage-dump' => 'Dump', |
| 2842 | + 'securepoll-subpage-tally' => 'Összesítés', |
| 2843 | + 'securepoll-tally-title' => 'Összesítés: $1', |
| 2844 | + 'securepoll-tally-not-finished' => 'Sajnos nem tudod összesíteni a választást amíg a szavazás le nem zárult.', |
| 2845 | + 'securepoll-can-decrypt' => 'A szavazási jegyzőkönyvet titkosították, de a feloldókulcs elérhető. |
| 2846 | +Választhatod az adatbázisban szereplő eredmények összesítését vagy a titkosított eredmények összesítését egy feltöltött fájlból.', |
| 2847 | + 'securepoll-tally-no-key' => 'Nem lehet a szavazást összesíteni, mert a szavazatokat titkosították és a feloldókulcs nem elérhető.', |
| 2848 | + 'securepoll-tally-local-legend' => 'Tárolt eredmények összesítése', |
| 2849 | + 'securepoll-tally-local-submit' => 'Összesítés készítése', |
| 2850 | + 'securepoll-tally-upload-legend' => 'Titkosított dump feltöltése', |
| 2851 | + 'securepoll-tally-upload-submit' => 'Összesítés készítése', |
| 2852 | + 'securepoll-tally-error' => 'Hiba a szavazási jegyzőkönyv értelmezésében, nem lehetett összesítést készíteni.', |
| 2853 | + 'securepoll-no-upload' => 'Semmilyen fájlt nem töltöttek fel, az eredményt így nem lehet összesíteni.', |
| 2854 | + 'securepoll-dump-corrupt' => 'A dump fájl hibás, nem sikerült feldolgozni.', |
| 2855 | + 'securepoll-tally-upload-error' => 'Hiba a dump fájl összesítésekor: $1', |
2402 | 2856 | ); |
2403 | 2857 | |
2404 | 2858 | /** Interlingua (Interlingua) |
— | — | @@ -2448,6 +2902,9 @@ |
2449 | 2903 | 'securepoll-jump' => 'Ir al servitor de votation', |
2450 | 2904 | 'securepoll-bad-ballot-submission' => 'Tu voto esseva invalide: $1', |
2451 | 2905 | 'securepoll-unanswered-questions' => 'Tu debe responder a tote le questiones.', |
| 2906 | + 'securepoll-invalid-rank' => 'Rango invalide. Tu debe dar al candidatos un rango inter 1 e 999.', |
| 2907 | + 'securepoll-unranked-options' => 'Alcun optiones non ha un rango. |
| 2908 | +Tu debe dar a tote le optiones un rango inter 1 e 999.', |
2452 | 2909 | 'securepoll-remote-auth-error' => 'Error durante le lectura del informationes de tu conto ab le servitor.', |
2453 | 2910 | 'securepoll-remote-parse-error' => 'Error durante le interpretation del responsa de autorisation ab le servitor.', |
2454 | 2911 | 'securepoll-api-invalid-params' => 'Parametros invalide.', |
— | — | @@ -2472,6 +2929,7 @@ |
2473 | 2930 | 'securepoll-strike-reason' => 'Motivo:', |
2474 | 2931 | 'securepoll-strike-cancel' => 'Annullar', |
2475 | 2932 | 'securepoll-strike-error' => 'Error durante le cancellation/restauration: $1', |
| 2933 | + 'securepoll-strike-token-mismatch' => 'Datos de session perdite', |
2476 | 2934 | 'securepoll-details-link' => 'Detalios', |
2477 | 2935 | 'securepoll-details-title' => 'Detalios del voto: #$1', |
2478 | 2936 | 'securepoll-invalid-vote' => '"$1" non es un identificator valide de un voto', |
— | — | @@ -2487,6 +2945,8 @@ |
2488 | 2946 | 'securepoll-dump-not-finished' => 'Le registro cryptate del election non essera disponibile usque le data final: le $1 a $2', |
2489 | 2947 | 'securepoll-dump-no-urandom' => 'Impossibile aperir /dev/urandom. |
2490 | 2948 | Pro mantener le confidentialitate del votatores, le registro cryptate del election non essera disponibile al publico usque illo pote esser miscite con un fluxo secur de numeros aleatori.', |
| 2949 | + 'securepoll-urandom-not-supported' => 'Iste servitor non supporta le generation de numeros aleatori cryptographic. |
| 2950 | +Pro assecurar le confidentialitate del votatores, le datos cryptate del election es solo publicamente disponibile si illos pote esser miscite con un fluxo de numeros aleatori secur.', |
2491 | 2951 | 'securepoll-translate-title' => 'Traducer: $1', |
2492 | 2952 | 'securepoll-invalid-language' => 'Le codice de lingua "$1" es invalide', |
2493 | 2953 | 'securepoll-submit-translate' => 'Actualisar', |
— | — | @@ -2511,9 +2971,12 @@ |
2512 | 2972 | 'securepoll-tally-upload-submit' => 'Contar resultatos', |
2513 | 2973 | 'securepoll-tally-error' => 'Error durante le interpretation del registro de voto; non pote producer un conto.', |
2514 | 2974 | 'securepoll-no-upload' => 'Nulle file ha essite cargate; non pote contar le resultatos.', |
| 2975 | + 'securepoll-dump-corrupt' => 'Le file de dump es corrumpite e non pote esser processate.', |
| 2976 | + 'securepoll-tally-upload-error' => 'Error de contar ex le file de dump: $1', |
2515 | 2977 | ); |
2516 | 2978 | |
2517 | 2979 | /** Indonesian (Bahasa Indonesia) |
| 2980 | + * @author Bennylin |
2518 | 2981 | * @author Rex |
2519 | 2982 | */ |
2520 | 2983 | $messages['id'] = array( |
— | — | @@ -2558,10 +3021,11 @@ |
2559 | 3022 | 'securepoll-no-decryption-key' => 'Kunci dekripsi belum dikonfigurasikan. |
2560 | 3023 | Tidak dapat melakukan dekripsi.', |
2561 | 3024 | 'securepoll-jump' => 'Pergi ke server pemungutan suara', |
2562 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
2563 | | -Suara Anda tidak valid: $1 |
2564 | | -</div>', |
| 3025 | + 'securepoll-bad-ballot-submission' => 'Suara Anda tidak valid: $1', |
2565 | 3026 | 'securepoll-unanswered-questions' => 'Anda harus menjawab semua pertanyaan.', |
| 3027 | + 'securepoll-invalid-rank' => 'Peringat tidak sah. Anda harus memberi peringkat kandidat antara 1 dan 99.', |
| 3028 | + 'securepoll-unranked-options' => 'Beberapa pilihan tidak diberi peringkat. |
| 3029 | +Anda harus memberi peringkat antara 1 dan 99 untuk semua pilihan.', |
2566 | 3030 | 'securepoll-remote-auth-error' => 'Terjadi kesalahan ketika menarik informasi akun Anda dari server.', |
2567 | 3031 | 'securepoll-remote-parse-error' => 'Terjadi kesalahan interpretasi atas respons otorisasi dari server.', |
2568 | 3032 | 'securepoll-api-invalid-params' => 'Parameter tidak valid.', |
— | — | @@ -2582,10 +3046,11 @@ |
2583 | 3047 | 'securepoll-header-strike' => 'Coret', |
2584 | 3048 | 'securepoll-header-details' => 'Rincian', |
2585 | 3049 | 'securepoll-strike-button' => 'Coret', |
2586 | | - 'securepoll-unstrike-button' => 'Batal coret', |
| 3050 | + 'securepoll-unstrike-button' => 'Hapus coretan', |
2587 | 3051 | 'securepoll-strike-reason' => 'Alasan:', |
2588 | | - 'securepoll-strike-cancel' => 'Batal', |
| 3052 | + 'securepoll-strike-cancel' => 'Batalkan', |
2589 | 3053 | 'securepoll-strike-error' => 'Gagal mencoret/membatalkan pencoretan: $1', |
| 3054 | + 'securepoll-strike-token-mismatch' => 'Data sesi terhilang', |
2590 | 3055 | 'securepoll-details-link' => 'Rincian', |
2591 | 3056 | 'securepoll-details-title' => 'Rincian suara: #$1', |
2592 | 3057 | 'securepoll-invalid-vote' => 'ID suara tidak sah: "$1"', |
— | — | @@ -2601,6 +3066,8 @@ |
2602 | 3067 | 'securepoll-dump-not-finished' => 'Catatan pemilihan terenkripsi hanya tersedia setelah selesainya pemungutan suara pada $2, $1.', |
2603 | 3068 | 'securepoll-dump-no-urandom' => 'Tidak dapat membuka /dev/urandom. |
2604 | 3069 | Untuk memastikan privasi pemberi suara, catatan pemilihan terenkripsi hanya akan tersedia secara publik jika menggunakan sebuah rangkaian nomor keamanan acak.', |
| 3070 | + 'securepoll-urandom-not-supported' => 'Peladen ini tidak mendukung kriptografi pembuatan angka acak. |
| 3071 | +Untuk menjaga kerahasiaan pemilih, catatan pemilihan ter-enkripsi hanya tersedia secara publik jika catatan tersebut dapat diacak dengan angka acak yang aman.', |
2605 | 3072 | 'securepoll-translate-title' => 'Terjemahkan: $1', |
2606 | 3073 | 'securepoll-invalid-language' => 'Kode bahasa tidak sah "$1"', |
2607 | 3074 | 'securepoll-submit-translate' => 'Perbarui', |
— | — | @@ -2625,11 +3092,22 @@ |
2626 | 3093 | 'securepoll-tally-upload-submit' => 'Membuat perhitungan', |
2627 | 3094 | 'securepoll-tally-error' => 'Terjadi kesalahan dalam menginterpretasikan catatan pemungutan suara, tidak dapat melakukan penghitungan.', |
2628 | 3095 | 'securepoll-no-upload' => 'Tidak ada berkas yang dimuatkan, tidak dapat melakukan penghitungan hasil.', |
| 3096 | + 'securepoll-dump-corrupt' => 'Berkas dump terkorpusi dan tidak dapat diproses.', |
| 3097 | + 'securepoll-tally-upload-error' => 'Kesalahan pada saat menjumlah berkas dump: $1', |
2629 | 3098 | ); |
2630 | 3099 | |
| 3100 | +/** Ido (Ido) |
| 3101 | + * @author Wyvernoid |
| 3102 | + */ |
| 3103 | +$messages['io'] = array( |
| 3104 | + 'securepoll' => 'SekuraVoto', |
| 3105 | + 'securepoll-desc' => 'Extensilo por elekti e voti', |
| 3106 | +); |
| 3107 | + |
2631 | 3108 | /** Italian (Italiano) |
2632 | 3109 | * @author BrokenArrow |
2633 | 3110 | * @author Darth Kule |
| 3111 | + * @author Massimiliano Lincetto |
2634 | 3112 | * @author Melos |
2635 | 3113 | * @author Nemo bis |
2636 | 3114 | * @author Pietrodn |
— | — | @@ -2678,10 +3156,11 @@ |
2679 | 3157 | 'securepoll-no-decryption-key' => 'Nessuna chiave di decrittazione è configurata. |
2680 | 3158 | Impossibile decifrare.', |
2681 | 3159 | 'securepoll-jump' => 'Vai al server della votazione', |
2682 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
2683 | | -Il tuo voto non era valido: $1 |
2684 | | -</div>', |
| 3160 | + 'securepoll-bad-ballot-submission' => 'Il tuo voto non era valido: $1', |
2685 | 3161 | 'securepoll-unanswered-questions' => 'È necessario rispondere a tutte le domande.', |
| 3162 | + 'securepoll-invalid-rank' => 'Voto non valido. Devi dare ai candidati un voto compreso tra 1 e 999.', |
| 3163 | + 'securepoll-unranked-options' => 'Alcune voci sono prive di voto. |
| 3164 | +Devi assegnare a ciascuna voce un voto compreso tra 1 e 999.', |
2686 | 3165 | 'securepoll-remote-auth-error' => 'Errore durante il recupero delle informazioni sul tuo account dal server.', |
2687 | 3166 | 'securepoll-remote-parse-error' => "Errore nell'interpretare la risposta di autorizzazione dal server.", |
2688 | 3167 | 'securepoll-api-invalid-params' => 'Parametri non validi.', |
— | — | @@ -2698,6 +3177,7 @@ |
2699 | 3178 | 'securepoll-header-voter-name' => 'Nome', |
2700 | 3179 | 'securepoll-header-voter-domain' => 'Dominio', |
2701 | 3180 | 'securepoll-header-ua' => 'Agente utente', |
| 3181 | + 'securepoll-header-cookie-dup' => 'Dup', |
2702 | 3182 | 'securepoll-header-strike' => 'Annulla', |
2703 | 3183 | 'securepoll-header-details' => 'Dettagli', |
2704 | 3184 | 'securepoll-strike-button' => 'Annulla questo voto', |
— | — | @@ -2705,6 +3185,7 @@ |
2706 | 3186 | 'securepoll-strike-reason' => 'Motivo:', |
2707 | 3187 | 'securepoll-strike-cancel' => 'Annulla', |
2708 | 3188 | 'securepoll-strike-error' => "Errore durante l'annullamento o ripristino del voto: $1", |
| 3189 | + 'securepoll-strike-token-mismatch' => 'I dati della sessione sono andati perduti.', |
2709 | 3190 | 'securepoll-details-link' => 'Dettagli', |
2710 | 3191 | 'securepoll-details-title' => 'Dettagli del voto: #$1', |
2711 | 3192 | 'securepoll-invalid-vote' => '"$1" non è l\'ID di un voto valido', |
— | — | @@ -2715,10 +3196,13 @@ |
2716 | 3197 | 'securepoll-header-reason' => 'Motivo', |
2717 | 3198 | 'securepoll-header-admin' => 'Amministratore', |
2718 | 3199 | 'securepoll-cookie-dup-list' => 'Utenti doppi per cookie', |
| 3200 | + 'securepoll-dump-title' => 'File di dump: $1', |
2719 | 3201 | 'securepoll-dump-no-crypt' => "Per questa elezione non è disponibile nessuna registrazione criptata, perché l'elezione non è impostata per usare la crittazione.", |
2720 | 3202 | 'securepoll-dump-not-finished' => "Le registrazioni criptate dell'elezione sono disponibili solo dopo la data di conclusione: $1 alle $2", |
2721 | 3203 | 'securepoll-dump-no-urandom' => "Impossibile aprire /dev/urandom. |
2722 | 3204 | Per proteggere la riservatezza dei votanti, le registrazioni criptate dell'elezione sono disponibili pubblicamente solo quando potranno essere mescolate con un flusso sicuro di numeri casuali.", |
| 3205 | + 'securepoll-urandom-not-supported' => 'Questo server non supporta la generazione di numeri casuali per la crittografia. |
| 3206 | +Al fine di garantire la privacy dei votanti, la procedura di votazione cifrata è pubblicamente utilizzabile quando è disponibile un generatore di numeri casuali per la crittografia del flusso di dati.', |
2723 | 3207 | 'securepoll-translate-title' => 'Traduci: $1', |
2724 | 3208 | 'securepoll-invalid-language' => 'Codice lingua non valido: "$1"', |
2725 | 3209 | 'securepoll-submit-translate' => 'Aggiorna', |
— | — | @@ -2730,6 +3214,21 @@ |
2731 | 3215 | 'securepoll-subpage-vote' => 'Vota', |
2732 | 3216 | 'securepoll-subpage-translate' => 'Traduci', |
2733 | 3217 | 'securepoll-subpage-list' => 'Elenca', |
| 3218 | + 'securepoll-subpage-dump' => 'File di dump', |
| 3219 | + 'securepoll-subpage-tally' => 'Conteggio', |
| 3220 | + 'securepoll-tally-title' => 'Conteggio: $1', |
| 3221 | + 'securepoll-tally-not-finished' => 'Non puoi effettuare il conteggio dei voti prima che la votazione sia terminata.', |
| 3222 | + 'securepoll-can-decrypt' => "Le informazioni relative all'elezione sono state cifrate, ma è disponibile la chiave di decifratura. |
| 3223 | +Puoi scegliere di effettuare il conteggio dei risultati presenti nel database o di effettuare il conteggio dei risultati cifrati contenuti in un file caricato.", |
| 3224 | + 'securepoll-tally-no-key' => 'Non puoi effettuare il conteggio dei risultati di questa elezione poiché i voti sono cifrati e la chiave di decifrazione non è disponibile.', |
| 3225 | + 'securepoll-tally-local-legend' => 'Effettua il conteggio dei risultati memorizzati.', |
| 3226 | + 'securepoll-tally-local-submit' => 'Crea conteggio', |
| 3227 | + 'securepoll-tally-upload-legend' => 'Carica un file di dump cifrato', |
| 3228 | + 'securepoll-tally-upload-submit' => 'Crea conteggio', |
| 3229 | + 'securepoll-tally-error' => "Errore nell'elaborazione delle informazioni del voto, non è possibile effettuare il conteggio.", |
| 3230 | + 'securepoll-no-upload' => 'Nessun file è stato caricato, non è possibile effettuare il conteggio.', |
| 3231 | + 'securepoll-dump-corrupt' => 'Il file di dump è corrotto e non può essere elaborato.', |
| 3232 | + 'securepoll-tally-upload-error' => "Errore nell'effettuare il conteggio sul file di dump: $1", |
2734 | 3233 | ); |
2735 | 3234 | |
2736 | 3235 | /** Japanese (日本語) |
— | — | @@ -2775,13 +3274,15 @@ |
2776 | 3275 | 'securepoll-jump' => '投票サーバへ移動', |
2777 | 3276 | 'securepoll-bad-ballot-submission' => 'あなたの投票は無効でした: $1', |
2778 | 3277 | 'securepoll-unanswered-questions' => 'すべての質問に答えなくてはなりません。', |
| 3278 | + 'securepoll-invalid-rank' => '順位が無効です。各候補に対しては1から999の間で順位を付けなければなりません。', |
| 3279 | + 'securepoll-unranked-options' => '順位が付けられていない選択肢があります。すべての選択肢に1から999の間で順位を付けなければなりません。', |
2779 | 3280 | 'securepoll-remote-auth-error' => 'エラー:サーバからあなたのアカウント情報を取得できませんでした', |
2780 | 3281 | 'securepoll-remote-parse-error' => 'サーバーからの認証応答の解釈に失敗しました。', |
2781 | 3282 | 'securepoll-api-invalid-params' => '不正なパラメータ。', |
2782 | 3283 | 'securepoll-api-no-user' => '指定されたIDをもつ利用者が見つかりません。', |
2783 | 3284 | 'securepoll-api-token-mismatch' => 'セキュリティ・トークンが一致しないのでログインできません。', |
2784 | 3285 | 'securepoll-not-logged-in' => 'この投票に参加するためにはログインしていなければいけません', |
2785 | | - 'securepoll-too-few-edits' => '申し訳ありませんが、あなたは投票できません。この投票に参加するためには少なくとも$1回の編集を行なっていなければなりません。現在の編集回数は$2です。', |
| 3286 | + 'securepoll-too-few-edits' => '申し訳ありませんが、あなたは投票できません。この投票に参加するためには少なくとも$1{{PLURAL:$1|回}}の編集を行なっていなければなりません。現在の編集回数は$2です。', |
2786 | 3287 | 'securepoll-blocked' => '申し訳ありませんが、あなたは投稿ブロックを受けているためこの投票に参加できません。', |
2787 | 3288 | 'securepoll-bot' => '申し訳ありませんが、ボットフラグのあるアカウントはこの選挙で投票することが許可されていません。', |
2788 | 3289 | 'securepoll-not-in-group' => '$1グループに属する利用者のみがこの投票に参加できます。', |
— | — | @@ -2799,6 +3300,7 @@ |
2800 | 3301 | 'securepoll-strike-reason' => '理由:', |
2801 | 3302 | 'securepoll-strike-cancel' => 'キャンセル', |
2802 | 3303 | 'securepoll-strike-error' => '抹消あるいは抹消撤回の実行に失敗: $1', |
| 3304 | + 'securepoll-strike-token-mismatch' => 'セッション情報消失', |
2803 | 3305 | 'securepoll-details-link' => '詳細', |
2804 | 3306 | 'securepoll-details-title' => '票の詳細: #$1', |
2805 | 3307 | 'securepoll-invalid-vote' => '"$1"は有効な票IDではありません', |
— | — | @@ -2813,6 +3315,7 @@ |
2814 | 3316 | 'securepoll-dump-no-crypt' => 'この選挙は暗号化を利用するように設定されていないため、暗号化された選挙記録は入手できません。', |
2815 | 3317 | 'securepoll-dump-not-finished' => '暗号化された選挙記録は終了日の$1 $2以降にのみ入手できます', |
2816 | 3318 | 'securepoll-dump-no-urandom' => '/dev/urandom を開けません。投票者のプライバシーを守るため、暗号化された選挙記録は暗号用乱数ストリームでシャッフルできる場合のみ公に入手できます。', |
| 3319 | + 'securepoll-urandom-not-supported' => 'このサーバーは暗号学的乱数生成に対応していません。投票者のプライバシーを守るため、暗号化された選挙記録は暗号用乱数ストリームでシャッフルできる場合のみ公に入手できます。', |
2817 | 3320 | 'securepoll-translate-title' => '翻訳: $1', |
2818 | 3321 | 'securepoll-invalid-language' => '「$1」は無効な言語コードです', |
2819 | 3322 | 'securepoll-submit-translate' => '更新', |
— | — | @@ -2838,6 +3341,62 @@ |
2839 | 3342 | 'securepoll-no-upload' => 'ファイルがアップロードされておらず、結果を集計できません。', |
2840 | 3343 | ); |
2841 | 3344 | |
| 3345 | +/** Georgian (ქართული) |
| 3346 | + * @author David1010 |
| 3347 | + * @author გიორგიმელა |
| 3348 | + */ |
| 3349 | +$messages['ka'] = array( |
| 3350 | + 'securepoll' => 'უსაფრთხო კეჭისყრა', |
| 3351 | + 'securepoll-invalid-election' => '"$1" არ წარმოადგენს არჩევნებისათვის დასაშვებ იდენტიფიკატორს.', |
| 3352 | + 'securepoll-welcome' => '<strong>კეთილი იყოს თქვენი მობრძანება $1!</strong>', |
| 3353 | + 'securepoll-submit' => 'ხმის მიცემა', |
| 3354 | + 'securepoll-thanks' => 'გმადლობთ, თქვენი ხმა მიღებულია.', |
| 3355 | + 'securepoll-return' => 'დაბრუნება $1–ზე', |
| 3356 | + 'securepoll-full-gpg-error' => 'შეცდომა GPG შესრულებისას: |
| 3357 | + |
| 3358 | +ბრძანება: $1 |
| 3359 | + |
| 3360 | +შეცდომა: |
| 3361 | +<pre>$2</pre>', |
| 3362 | + 'securepoll-jump' => 'ხმის მიცემის სერვერზე გადასვლა', |
| 3363 | + 'securepoll-bad-ballot-submission' => 'თქვენი ხმა ძალადაკარგულია: $1', |
| 3364 | + 'securepoll-unanswered-questions' => 'თქვენ უნდა უპასუხოთ ყველა შეკითხვას.', |
| 3365 | + 'securepoll-remote-auth-error' => 'შეცდომა ანგარიშზე ინფორმაციის მიღებისას სერვერიდან.', |
| 3366 | + 'securepoll-api-invalid-params' => 'არასწორი პარამეტრები.', |
| 3367 | + 'securepoll-api-no-user' => 'მომხმარებელი მითითებული იდენტიფიკატორით ვერ მოიძებნა.', |
| 3368 | + 'securepoll-list-title' => 'ხმების სია: $1', |
| 3369 | + 'securepoll-header-timestamp' => 'დრო', |
| 3370 | + 'securepoll-header-voter-name' => 'სახელი', |
| 3371 | + 'securepoll-header-voter-domain' => 'დომენი', |
| 3372 | + 'securepoll-header-ua' => 'მომხმარებლის აგენტი', |
| 3373 | + 'securepoll-header-details' => 'დეტალები', |
| 3374 | + 'securepoll-strike-reason' => 'მიზეზი:', |
| 3375 | + 'securepoll-strike-cancel' => 'გაუქმება', |
| 3376 | + 'securepoll-strike-token-mismatch' => 'სესიის მონაცემების დაკარგვა', |
| 3377 | + 'securepoll-details-link' => 'დეტალები', |
| 3378 | + 'securepoll-details-title' => 'ხმის მიცემის დეტალები: #$1', |
| 3379 | + 'securepoll-invalid-vote' => '"$1" არ წარმოადგენს ხმის მიცემისთვის დასაშვებ იდენტიფიკატორს', |
| 3380 | + 'securepoll-header-voter-type' => 'ხმის მიმცემის ტიპი', |
| 3381 | + 'securepoll-header-url' => 'URL', |
| 3382 | + 'securepoll-header-action' => 'მოქმედება', |
| 3383 | + 'securepoll-header-reason' => 'მიზეზი', |
| 3384 | + 'securepoll-header-admin' => 'ადმინი', |
| 3385 | + 'securepoll-translate-title' => 'თარგმნა: $1', |
| 3386 | + 'securepoll-submit-translate' => 'განახლება', |
| 3387 | + 'securepoll-language-label' => 'ენის არჩევა:', |
| 3388 | + 'securepoll-submit-select-lang' => 'თარგმნა', |
| 3389 | + 'securepoll-header-title' => 'სახელი', |
| 3390 | + 'securepoll-header-start-date' => 'დაწყების თარიღი', |
| 3391 | + 'securepoll-header-end-date' => 'დასრულების თარიღი', |
| 3392 | + 'securepoll-subpage-vote' => 'ხმის მიცემა', |
| 3393 | + 'securepoll-subpage-translate' => 'თარგმნა', |
| 3394 | + 'securepoll-subpage-list' => 'სია', |
| 3395 | + 'securepoll-subpage-tally' => 'დათვლა', |
| 3396 | + 'securepoll-tally-title' => 'დათვლა: $1', |
| 3397 | + 'securepoll-tally-local-submit' => 'დათვლის წარმოება', |
| 3398 | + 'securepoll-tally-upload-submit' => 'დათვლის წარმოება', |
| 3399 | +); |
| 3400 | + |
2842 | 3401 | /** Korean (한국어) |
2843 | 3402 | * @author Kwj2772 |
2844 | 3403 | * @author Mhha |
— | — | @@ -2886,10 +3445,11 @@ |
2887 | 3446 | 'securepoll-no-decryption-key' => '암호 해독 키가 설정되지 않았습니다. |
2888 | 3447 | 암호를 해독할 수 없습니다.', |
2889 | 3448 | 'securepoll-jump' => '선거 서버로 이동하기', |
2890 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
2891 | | -당신의 투표가 무효화되었습니다: $1 |
2892 | | -</div>', |
| 3449 | + 'securepoll-bad-ballot-submission' => '당신의 투표가 무효화되었습니다: $1', |
2893 | 3450 | 'securepoll-unanswered-questions' => '모든 질문에 답을 하셔야 합니다.', |
| 3451 | + 'securepoll-invalid-rank' => '순위를 잘못 입력하였습니다. 당신은 후보자의 순위를 1부터 999까지 매겨야 합니다.', |
| 3452 | + 'securepoll-unranked-options' => '어떤 선택 사항에 대한 순위가 매겨지지 않았습니다. |
| 3453 | +당신은 모든 선택 사항에 대해 1부터 999까지 순위를 매겨야 합니다.', |
2894 | 3454 | 'securepoll-remote-auth-error' => '귀하의 계정 정보를 불러오는 중에 오류가 발생하였습니다.', |
2895 | 3455 | 'securepoll-remote-parse-error' => '서버로부터 권한 응답에 따른 해석 오류가 발생', |
2896 | 3456 | 'securepoll-api-invalid-params' => '명령 변수가 잘못되었습니다.', |
— | — | @@ -2914,6 +3474,7 @@ |
2915 | 3475 | 'securepoll-strike-reason' => '이유:', |
2916 | 3476 | 'securepoll-strike-cancel' => '취소', |
2917 | 3477 | 'securepoll-strike-error' => '무효화/해제 과정에서 오류가 발생하였습니다: $1', |
| 3478 | + 'securepoll-strike-token-mismatch' => '세션 데이터가 손실되었습니다.', |
2918 | 3479 | 'securepoll-details-link' => '상세한 설명', |
2919 | 3480 | 'securepoll-details-title' => '투표 설명: #$1', |
2920 | 3481 | 'securepoll-invalid-vote' => '"$1"은 투표할 수 있는 ID가 아닙니다.', |
— | — | @@ -2929,6 +3490,8 @@ |
2930 | 3491 | 'securepoll-dump-not-finished' => '암호화된 선거 기록은 오직 마지막 기한인 $1 $2가 지난 뒤에야 이용하실 수 있습니다.', |
2931 | 3492 | 'securepoll-dump-no-urandom' => '/dev/urandom을 열 수 없습니다. |
2932 | 3493 | 투표자의 사생활을 보호하기 위해서, 암호화된 선거 기록은 안전한 무작위 숫자 흐름으로 뒤섞일 수 있을 때 오직 공적으로 이용 가능합니다.', |
| 3494 | + 'securepoll-urandom-not-supported' => '이 서버는 암호화 난수 생성을 지원하지 않습니다. |
| 3495 | +투표자의 개인 정보를 유지하기 위해, 선거 기록이 안전한 무작위 수열로 변환될 수 있을 경우에만 암호화된 선거 기록이 공개될 것입니다.', |
2933 | 3496 | 'securepoll-translate-title' => '번역: $1', |
2934 | 3497 | 'securepoll-invalid-language' => '"$1"은 인식되지 않는 언어 코드입니다.', |
2935 | 3498 | 'securepoll-submit-translate' => '갱신', |
— | — | @@ -2953,6 +3516,8 @@ |
2954 | 3517 | 'securepoll-tally-upload-submit' => '개표하기', |
2955 | 3518 | 'securepoll-tally-error' => '투표 기록의 해석에 오류가 생겨서, 계정을 만들 수 없습니다.', |
2956 | 3519 | 'securepoll-no-upload' => '파일이 올려지지 않아서, 결과를 집계할 수 없습니다.', |
| 3520 | + 'securepoll-dump-corrupt' => '기록 파일에 문제가 있어서 처리할 수 없습니다.', |
| 3521 | + 'securepoll-tally-upload-error' => '기록 파일을 개표하는 중 오류 발생: $1', |
2957 | 3522 | ); |
2958 | 3523 | |
2959 | 3524 | /** Ripoarisch (Ripoarisch) |
— | — | @@ -3003,6 +3568,9 @@ |
3004 | 3569 | 'securepoll-jump' => 'Jangk op dä Server för de Afshtemmung', |
3005 | 3570 | 'securepoll-bad-ballot-submission' => 'Ding Shtemm woh nit jöltesch: $1', |
3006 | 3571 | 'securepoll-unanswered-questions' => 'Do moß op alle Froore en Antwoot jävve.', |
| 3572 | + 'securepoll-invalid-rank' => 'Dat es ene verkeehte Rang. Do moß Dinge Kandidaate ene Rang zwesche 1 un 999 jävve.', |
| 3573 | + 'securepoll-unranked-options' => 'Ene Deil vun dä Müjjeleschkeite hät keine Rang. |
| 3574 | +Do moß alle Müjjeleschkeite ene Rang zwesche 1 un 999 jevve.', |
3007 | 3575 | 'securepoll-remote-auth-error' => 'Ene Fähler es opjetrodde, wi mer däm Server öm Ding Daate jefrooch hann.', |
3008 | 3576 | 'securepoll-remote-parse-error' => 'Ene Fähler es opjetrodde. Mer kunnte met däm Server singem Zoshtemmungs_Kood nix aanfange.', |
3009 | 3577 | 'securepoll-api-invalid-params' => 'Verkeehte Parrameeterre.', |
— | — | @@ -3028,6 +3596,7 @@ |
3029 | 3597 | 'securepoll-strike-reason' => 'Aaanlaß o Jrund:', |
3030 | 3598 | 'securepoll-strike-cancel' => 'Ophüre!', |
3031 | 3599 | 'securepoll-strike-error' => 'Ene Fähler is opjetrodde beim Ußshtriishe odder widder zerök holle: $1', |
| 3600 | + 'securepoll-strike-token-mismatch' => 'De Sezungsdaate sin fott', |
3032 | 3601 | 'securepoll-details-link' => 'Einzelheite', |
3033 | 3602 | 'securepoll-details-title' => 'Einzelheite vun dä Shtemm met dä Kennong: „$1“', |
3034 | 3603 | 'securepoll-invalid-vote' => '„$1“ kein reschtijje Kännong för en Afshtemmung', |
— | — | @@ -3045,6 +3614,8 @@ |
3046 | 3615 | 'securepoll-dump-no-urandom' => 'Mer künne <code>/dev/random</code> nit opmaache. |
3047 | 3616 | Öm dä Afshtemmer ze schötze, don mer verschlößelte Datesäz bloß dann ußjävve, |
3048 | 3617 | wann mer se met enem seschere, zohfällije Dateshtrom verwörfelle künne.', |
| 3618 | + 'securepoll-urandom-not-supported' => 'Hee dä ßööver kann kein Zohfallszahle för et Verschößele maache. |
| 3619 | +Öm et Wahljeheimnis ze bewaahre, sin de verschößelte Opzeichnunge vun der Stemme bloß dann öffentlich ze han, wann mer se en ene seshere zofällije Reijefollsh zeije künne.', |
3049 | 3620 | 'securepoll-translate-title' => 'Övveräze: $1', |
3050 | 3621 | 'securepoll-invalid-language' => '„<code>$1</code>“ es enne onjöltijje Shprooche_Kood', |
3051 | 3622 | 'securepoll-header-trans-id' => 'Kennong', |
— | — | @@ -3070,6 +3641,8 @@ |
3071 | 3642 | 'securepoll-tally-upload-submit' => 'Lohß Jonn!', |
3072 | 3643 | 'securepoll-tally-error' => 'Beim Ungersöke vun ene Shtemm es jet donevve jejange, dröm künne mer nix ußzälle.', |
3073 | 3644 | 'securepoll-no-upload' => 'Nix huhjelaade, do künne mer kein Shtemme ußzälle.', |
| 3645 | + 'securepoll-dump-corrupt' => 'De <i lang="en">dump</i>-Dattei es kappoott un kann nit verärbeidt wääde.', |
| 3646 | + 'securepoll-tally-upload-error' => 'Ene Fähler es opjetrodde beim Ußzälle noh dä <i lang="en">dump</i>-Dattei: $1', |
3074 | 3647 | ); |
3075 | 3648 | |
3076 | 3649 | /** Luxembourgish (Lëtzebuergesch) |
— | — | @@ -3104,19 +3677,30 @@ |
3105 | 3678 | Är Stëmm gouf net gespäichert! |
3106 | 3679 | |
3107 | 3680 | $1', |
| 3681 | + 'securepoll-no-gpg-home' => 'De Basis-Repertoire GPG konnt net ugeluecht ginn.', |
| 3682 | + 'securepoll-secret-gpg-error' => 'Feeler beim Ausféiere vun GPG. |
| 3683 | +Benotzt $wgSecurePollShowErrorDetail=true; op LocalSettings.php fir méi Detailer ze gesinn.', |
| 3684 | + 'securepoll-full-gpg-error' => 'Feeler beim Ausféiere vun GPG: |
| 3685 | + |
| 3686 | +Kommando: $1 |
| 3687 | + |
| 3688 | +Feeler: |
| 3689 | +<pre>$2</pre>', |
3108 | 3690 | 'securepoll-gpg-config-error' => "D'GPG-Schlëssele sinn net korrekt konfiguréiert.", |
3109 | 3691 | 'securepoll-gpg-parse-error' => 'Feeler beim Interpretéieren vum GPG-Ouput', |
3110 | 3692 | 'securepoll-no-decryption-key' => 'Et ass keen Ëntschlësungsschlëssel agestallt. |
3111 | 3693 | Ëntschlësselung onméiglech.', |
3112 | 3694 | 'securepoll-jump' => 'Op den Ofstëmmungs-Server goen', |
3113 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
3114 | | -Är Stëmm ass net valabel: $1 |
3115 | | -</div>', |
| 3695 | + 'securepoll-bad-ballot-submission' => 'Är Stëmm ass net valabel: $1', |
3116 | 3696 | 'securepoll-unanswered-questions' => 'Dir musst all Froe beäntwerten', |
| 3697 | + 'securepoll-invalid-rank' => 'Ongëltegt Classement. Dir musst de Kandidaten e Classement tëschent 1 an 999 ginn.', |
| 3698 | + 'securepoll-unranked-options' => 'E puer Optioune krute kee Classement. |
| 3699 | +Dir musst allen optiounen e Classement tëschent 1 an 999 ginn.', |
3117 | 3700 | 'securepoll-remote-auth-error' => 'Feeler beim Ofruf vun Äre Benotzerkontinformatioune vum Server.', |
3118 | 3701 | 'securepoll-remote-parse-error' => 'Feeler beim Interpretéiere vun der Autorisatioun déi de Server geschéckt huet.', |
3119 | 3702 | 'securepoll-api-invalid-params' => 'Parameter déi net valabel sinn.', |
3120 | 3703 | 'securepoll-api-no-user' => 'Et gouf kee Benotzer mat der ID fonnt déi ugi war.', |
| 3704 | + 'securepoll-api-token-mismatch' => 'Falsche Sécerheeets-Token, Aloggen ass net méiglech.', |
3121 | 3705 | 'securepoll-not-logged-in' => 'Dir musst Iech aloggen fir bäi dëse Walen ofstëmmen ze kënnen', |
3122 | 3706 | 'securepoll-too-few-edits' => 'Pardon, Dir däerft net ofstëmmen. Dir musst mindestens $1 {{PLURAL:$1|Ännerung|Ännerunge}} gemaacht hun, fir bäi dëse Walen ofstëmmen ze kënnen, Dir hutt der $2 gemaach.', |
3123 | 3707 | 'securepoll-blocked' => 'Pardon, Dir kënnt net bäi dëse Walen ofstëmmen wann dir elo fir Ännerunge gespaart sidd.', |
— | — | @@ -3136,6 +3720,7 @@ |
3137 | 3721 | 'securepoll-strike-reason' => 'Grond:', |
3138 | 3722 | 'securepoll-strike-cancel' => 'Ofbriechen', |
3139 | 3723 | 'securepoll-strike-error' => 'Feeler beim Sträiche respektiv Ophiewe vum Sträichen: $1', |
| 3724 | + 'securepoll-strike-token-mismatch' => 'Verloscht vun den Donnéeë vun der Verbindung', |
3140 | 3725 | 'securepoll-details-link' => 'Detailer', |
3141 | 3726 | 'securepoll-details-title' => 'Detailer vun der Ofstëmmung: #$1', |
3142 | 3727 | 'securepoll-invalid-vote' => '"$1" ass keng valabel Ofstëmmngs-ID', |
— | — | @@ -3149,6 +3734,8 @@ |
3150 | 3735 | 'securepoll-dump-title' => 'Dump: $1', |
3151 | 3736 | 'securepoll-dump-no-crypt' => "Fir dës Wale gëtt et keng verschlësselt Donnéeë vun der Ofstëmmung, well d'Walen net esou agestallt sinn fir d'Verschlësselung ze benotzen.", |
3152 | 3737 | 'securepoll-dump-not-finished' => 'Verschlësselt Donnéeë vun de Wale sinn eréischt nom Enn vun de Walen den $1 ëm $2 disponibel', |
| 3738 | + 'securepoll-dump-no-urandom' => "/dev/urandom kann net opgemaach ginn. |
| 3739 | +Fir d'Konfidentialitéit vun de Wieler z'assuréieren, si verschlësselt Opzeechnunge vun de Walen nëmmen disponibel wa se mat engem sécheren Zoufallszuelestroum kënne gemescht ginn.", |
3153 | 3740 | 'securepoll-translate-title' => 'Iwwersetzen: $1', |
3154 | 3741 | 'securepoll-invalid-language' => 'Net valabele Sproochecode "$1"', |
3155 | 3742 | 'securepoll-submit-translate' => 'Aktualiséieren', |
— | — | @@ -3171,6 +3758,8 @@ |
3172 | 3759 | 'securepoll-tally-upload-submit' => 'Auszielung uleeën', |
3173 | 3760 | 'securepoll-tally-error' => "Feeler bäi der Interpretatioun vun de gespäicherten Donnéeë vun de Walen, d'Auszieleung kann net gemaach ginn.", |
3174 | 3761 | 'securepoll-no-upload' => "Et gouf kee Fichier eropgelueden, d'Resultater kënnen net ausgezielt ginn.", |
| 3762 | + 'securepoll-dump-corrupt' => 'Den Dump-Fichier ass futti a kann net verschafft ginn.', |
| 3763 | + 'securepoll-tally-upload-error' => 'Feeler bei der Auswertung vum Dump-Fichier: $1', |
3175 | 3764 | ); |
3176 | 3765 | |
3177 | 3766 | /** Limburgish (Limburgs) |
— | — | @@ -3220,9 +3809,7 @@ |
3221 | 3810 | 'securepoll-no-decryption-key' => "d'r Is geine decryptiesjleutel ingesjteld. |
3222 | 3811 | Decodere is neet meugelik.", |
3223 | 3812 | 'securepoll-jump' => 'Gank nao de sjtömserver', |
3224 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
3225 | | -Dien sjtöm is óngeldig: $1 |
3226 | | -</div>', |
| 3813 | + 'securepoll-bad-ballot-submission' => 'Dien sjtöm is óngeldig: $1', |
3227 | 3814 | 'securepoll-unanswered-questions' => 'Doe mós alle vraoge beantjwaorde.', |
3228 | 3815 | 'securepoll-remote-auth-error' => "d'r Is 'n fout opgetraoje bie 't ophaole van dien gebroekersinformatie van de server.", |
3229 | 3816 | 'securepoll-remote-parse-error' => "d'r Is 'n fout opgetraoje bie 't interpretere van 't antjwaord van de server.", |
— | — | @@ -3285,18 +3872,113 @@ |
3286 | 3873 | * @author Matasg |
3287 | 3874 | */ |
3288 | 3875 | $messages['lt'] = array( |
| 3876 | + 'securepoll' => 'Saugus balsavimas', |
| 3877 | + 'securepoll-desc' => 'Priemonė rinkimams ir apklausoms', |
| 3878 | + 'securepoll-invalid-page' => 'Netinkamas subpuslapis "<nowiki>$1</nowiki>"', |
| 3879 | + 'securepoll-need-admin' => 'Jei norite atlikti šį veiksmą, Jums reikia administratoriumi.', |
| 3880 | + 'securepoll-too-few-params' => 'Nepakanka subpuslapio parametrų (negalioja nuoroda).', |
3289 | 3881 | 'securepoll-invalid-election' => '"$1" nėra tinkamas rinkimų ID.', |
3290 | 3882 | 'securepoll-welcome' => '<strong>Sveiki $1!</strong>', |
| 3883 | + 'securepoll-not-started' => 'Šie rinkimai dar nėra prasidėję. |
| 3884 | +Jie turėtų prasidėti $2 $3.', |
| 3885 | + 'securepoll-finished' => 'Šie rinkimai baigėsi, jūs nebegalite balsuoti.', |
| 3886 | + 'securepoll-not-qualified' => 'Jūs nesate kvalifikuotas balsuoti šiuose rinkimuose: $1', |
| 3887 | + 'securepoll-change-disallowed' => 'Jūs balsavote šiuose rinkimuose anksčiau. |
| 3888 | +Atsiprašome, jūs negalite balsuoti dar kartą.', |
| 3889 | + 'securepoll-change-allowed' => '<strong>Pastaba: Jūs balsavote anksčiau.</strong> |
| 3890 | +Galite pakeisti savo balsą, pasinaudodamas forma žemiau. |
| 3891 | +Jei tai padarysite, jūsų originalus balsavimas bus atmestas.', |
3291 | 3892 | 'securepoll-submit' => 'Balsuoti', |
| 3893 | + 'securepoll-gpg-receipt' => 'Dėkojame už balsą. |
| 3894 | + |
| 3895 | +Jei norite, galite nusikopijuoti išrašą, kaip įrodymą, kad balsavote: |
| 3896 | + |
| 3897 | +<pre>$1</pre>', |
3292 | 3898 | 'securepoll-thanks' => 'Ačiū, jūsų balsas buvo įrašytas.', |
3293 | 3899 | 'securepoll-return' => 'Grįžti į $1', |
| 3900 | + 'securepoll-encrypt-error' => 'Nepavyko užšifruoti jūsų balsavimo įrašo. |
| 3901 | +Jūsų balsavimas nebuvo užregistruotas! |
| 3902 | + |
| 3903 | +$1', |
| 3904 | + 'securepoll-no-gpg-home' => 'Nepavyko sukurti GPG katalogo.', |
| 3905 | + 'securepoll-secret-gpg-error' => 'GPG vykdymo klaida. |
| 3906 | +Naudokite $wgSecurePollShowErrorDetail=true; skripte LocalSettings.php jei norite sužinoti daugiau informacijos.', |
| 3907 | + 'securepoll-full-gpg-error' => 'GPG vykdymo klaida: |
| 3908 | + |
| 3909 | +Komanda: $1 |
| 3910 | + |
| 3911 | +Klaida: |
| 3912 | +<pre>$2</pre>', |
3294 | 3913 | 'securepoll-gpg-config-error' => 'GPG raktai sukonfigūruoti netinkamai.', |
| 3914 | + 'securepoll-gpg-parse-error' => 'Klaida interpretuojant GPG išeigą.', |
| 3915 | + 'securepoll-no-decryption-key' => 'Nėra sukonfigūruoto atkodavimo rakto. |
| 3916 | +Negalima iššifruoti.', |
3295 | 3917 | 'securepoll-jump' => 'Eiti į balsavimo serverį', |
3296 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
3297 | | -Jūsų balsas netinkamas: $1 |
3298 | | -</div>', |
| 3918 | + 'securepoll-bad-ballot-submission' => 'Jūsų balsas netinkamas: $1', |
| 3919 | + 'securepoll-unanswered-questions' => 'Turite atsakyti į visus klausimus.', |
| 3920 | + 'securepoll-remote-auth-error' => 'Įvyko klaida pristatant jūsų sąskaitos informaciją iš serverio.', |
| 3921 | + 'securepoll-remote-parse-error' => 'Klaida interpretuojant leidimo atsakymą iš serverio.', |
3299 | 3922 | 'securepoll-api-invalid-params' => 'Netinkami parametrai', |
3300 | 3923 | 'securepoll-api-no-user' => 'Nerastas naudotojas su duotu ID.', |
| 3924 | + 'securepoll-api-token-mismatch' => 'Saugos žymės nesutampa, negalite prisijungti', |
| 3925 | + 'securepoll-not-logged-in' => 'Jūs turite prisijungti, norėdami balsuoti šiuose rinkimuose', |
| 3926 | + 'securepoll-too-few-edits' => 'Atsiprašome, Jūs negalite balsuoti. Jūs privalote atlikti bent $1 {{PLURAL:$1|redagavimą|redagavimų}}, norėdami balsuoti šiuose rinkimuose. Jūs atlikote $2.', |
| 3927 | + 'securepoll-blocked' => 'Atsiprašome, Jūs negalite balsuoti šiuose rinkimuose jei dabar esate užblokuotas.', |
| 3928 | + 'securepoll-bot' => 'Atsiprašome, sąskaitos su boto statusu negali balsuoti šiuose rinkimuose.', |
| 3929 | + 'securepoll-not-in-group' => 'Tik nariai iš grupės "$1" gali balsuoti šiuose rinkimuose.', |
| 3930 | + 'securepoll-not-in-list' => 'Atsiprašome, Jūs nesate vartotojų sąraše, kuriems leidžiama balsuoti šiuose rinkimuose.', |
| 3931 | + 'securepoll-list-title' => 'Rodyti balsus: $1', |
| 3932 | + 'securepoll-header-timestamp' => 'Laikas', |
| 3933 | + 'securepoll-header-voter-name' => 'Vardas', |
| 3934 | + 'securepoll-header-voter-domain' => 'Domenas', |
| 3935 | + 'securepoll-header-ua' => 'Naudotojo agentas', |
| 3936 | + 'securepoll-header-cookie-dup' => 'Nuor.', |
| 3937 | + 'securepoll-header-strike' => 'Uždrausti', |
| 3938 | + 'securepoll-header-details' => 'Detalės', |
| 3939 | + 'securepoll-strike-button' => 'Uždrausti', |
| 3940 | + 'securepoll-unstrike-button' => 'Nebedrausti', |
| 3941 | + 'securepoll-strike-reason' => 'Priežastis:', |
| 3942 | + 'securepoll-strike-cancel' => 'Atšaukti', |
| 3943 | + 'securepoll-strike-error' => 'Klaida atliekant uždraudimą/nebedraudimą: $1', |
| 3944 | + 'securepoll-details-link' => 'Detalės', |
| 3945 | + 'securepoll-details-title' => 'Balsavimo detalės: #$1', |
| 3946 | + 'securepoll-invalid-vote' => '"$1" nėra teisingas balsavimo ID', |
| 3947 | + 'securepoll-header-voter-type' => 'Balsavusiojo tipas', |
| 3948 | + 'securepoll-voter-properties' => 'Balsuotojo savybės', |
| 3949 | + 'securepoll-strike-log' => 'Uždraudimo sąrašas', |
| 3950 | + 'securepoll-header-action' => 'Veiksmas', |
| 3951 | + 'securepoll-header-reason' => 'Priežastis', |
| 3952 | + 'securepoll-header-admin' => 'Administratorius', |
| 3953 | + 'securepoll-cookie-dup-list' => 'Cookie dublikuoti naudotojai', |
| 3954 | + 'securepoll-dump-title' => 'Išmestas: $1', |
| 3955 | + 'securepoll-dump-no-crypt' => 'Nėra prieinamas nė vienas šifruotas rinkimų įrašas, nes rinkimai nėra sukonfigūruoti naudoti kodavimą.', |
| 3956 | + 'securepoll-dump-not-finished' => 'Šifruoti rinkimų įrašai prieinami tik po $1 $2', |
| 3957 | + 'securepoll-dump-no-urandom' => 'Nepavyko atidaryti /dev/urandom. |
| 3958 | +Siekiant išlaikyti balsuotojų privatumą, šifruoti rinkimų įrašai viešai prieinami tik kai jie sumaišyti su saugiu atsitiktinių skaičių srautu.', |
| 3959 | + 'securepoll-translate-title' => 'Išversti: $1', |
| 3960 | + 'securepoll-invalid-language' => 'Neleistinas kalbos kodas "$1"', |
| 3961 | + 'securepoll-submit-translate' => 'Atnaujinti', |
| 3962 | + 'securepoll-language-label' => 'Pasirinkite kalbą:', |
| 3963 | + 'securepoll-submit-select-lang' => 'Išversti', |
| 3964 | + 'securepoll-header-title' => 'Pavadinimas', |
| 3965 | + 'securepoll-header-start-date' => 'Pradžios data', |
| 3966 | + 'securepoll-header-end-date' => 'Pabaigos data', |
| 3967 | + 'securepoll-subpage-vote' => 'Balsavimas', |
| 3968 | + 'securepoll-subpage-translate' => 'Vertimas', |
| 3969 | + 'securepoll-subpage-list' => 'Sąrašas', |
| 3970 | + 'securepoll-subpage-dump' => 'Perrašymas', |
| 3971 | + 'securepoll-subpage-tally' => 'Rezultatas', |
| 3972 | + 'securepoll-tally-title' => 'Rezultatas: $1', |
| 3973 | + 'securepoll-tally-not-finished' => 'Atsiprašome, Jūs negalite paskelbti rinkimų rezultato iki balsavimo baigties.', |
| 3974 | + 'securepoll-can-decrypt' => 'Rinkimų įrašas buvo šifruotas, tačiau iššifravimo raktas prieinamas. |
| 3975 | +Galite pasirinkti, ar sutampa rezultatai, esantys duomenų bazėje bei rezultatuoti šifruotus rezultatus iš įkelto failo.', |
| 3976 | + 'securepoll-tally-no-key' => 'Jūs negalite paskelbti šių rinkimų rezultatų, nes balsai yra koduoti ir iššifravimo rakto nėra.', |
| 3977 | + 'securepoll-tally-local-legend' => 'Paskelbti išsaugotus rezultatus', |
| 3978 | + 'securepoll-tally-local-submit' => 'Sukurti rezultatus', |
| 3979 | + 'securepoll-tally-upload-legend' => 'Įkelti šifruotą turinį', |
| 3980 | + 'securepoll-tally-upload-submit' => 'Sukurti rezultatus', |
| 3981 | + 'securepoll-tally-error' => 'Klaida interpretuojant balsavimo įrašą, negalima sukurti suvestinių.', |
| 3982 | + 'securepoll-no-upload' => 'Failas nebuvo įkeltas, negalima skaičiuoti rezultatų.', |
3301 | 3983 | ); |
3302 | 3984 | |
3303 | 3985 | /** Macedonian (Македонски) |
— | — | @@ -3356,9 +4038,7 @@ |
3357 | 4039 | 'securepoll-no-decryption-key' => 'Tiada kunci penyahsulitan dibentuk. |
3358 | 4040 | Tidak dapat menyahsulit.', |
3359 | 4041 | 'securepoll-jump' => 'Pergi ke pelayan undian', |
3360 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
3361 | | -Undi anda tak sah: $1 |
3362 | | -</div>', |
| 4042 | + 'securepoll-bad-ballot-submission' => 'Undi anda tak sah: $1', |
3363 | 4043 | 'securepoll-unanswered-questions' => 'Anda perlu jawab kesemua soalan.', |
3364 | 4044 | 'securepoll-remote-auth-error' => 'Ralat dalam mengambil maklumat akaun anda dari pelayan.', |
3365 | 4045 | 'securepoll-remote-parse-error' => 'Ralat menafsirkan jawapan kebenaran dari pelayan.', |
— | — | @@ -3386,8 +4066,158 @@ |
3387 | 4067 | 'securepoll-strike-error' => 'Ralat membuang/kembalikan: $1', |
3388 | 4068 | 'securepoll-details-link' => 'Lanjut', |
3389 | 4069 | 'securepoll-details-title' => 'Maklumat undi: #$1', |
| 4070 | + 'securepoll-invalid-vote' => '"$1" bukan ID undian yang sah', |
| 4071 | + 'securepoll-header-voter-type' => 'Jenis pengundi', |
| 4072 | + 'securepoll-voter-properties' => 'Sifat pengundi', |
| 4073 | + 'securepoll-strike-log' => 'Log pemotongan', |
| 4074 | + 'securepoll-header-action' => 'Tindakan', |
| 4075 | + 'securepoll-header-reason' => 'Sebab', |
| 4076 | + 'securepoll-header-admin' => 'Pentadbir', |
| 4077 | + 'securepoll-cookie-dup-list' => 'Pengguna salinan cookie', |
| 4078 | + 'securepoll-dump-title' => 'Longgokan: $1', |
| 4079 | + 'securepoll-dump-no-crypt' => 'Tiada rekod sulit pemilihan yang ada untuk pemilihan ini, kerana pemilihan tidak disusun untuk menggunakan penyulitan.', |
| 4080 | + 'securepoll-dump-not-finished' => 'Rekod sulit pemilihan hanya ada setelah tarikh tamat pada $1 pukul $2', |
| 4081 | + 'securepoll-dump-no-urandom' => 'Gagal membuka /dev/urandom. |
| 4082 | +Untuk mengekalkan privasi pengundi, rekod sulit pemilihan hanya tersedia untuk awam apabila ia dirombak dengan aliran nombor rawak yang selamat.', |
| 4083 | + 'securepoll-translate-title' => 'Terjemah: $1', |
| 4084 | + 'securepoll-invalid-language' => 'Kod bahasa tidak sah "$1"', |
| 4085 | + 'securepoll-submit-translate' => 'Kemas kini', |
| 4086 | + 'securepoll-language-label' => 'Pilih bahasa:', |
| 4087 | + 'securepoll-submit-select-lang' => 'Terjemah', |
| 4088 | + 'securepoll-header-title' => 'Nama', |
| 4089 | + 'securepoll-header-start-date' => 'Tarikh mula', |
| 4090 | + 'securepoll-header-end-date' => 'Tarikh tamat', |
| 4091 | + 'securepoll-subpage-vote' => 'Undi', |
| 4092 | + 'securepoll-subpage-translate' => 'Terjemah', |
| 4093 | + 'securepoll-subpage-list' => 'Senarai', |
| 4094 | + 'securepoll-subpage-dump' => 'Longgokan', |
| 4095 | + 'securepoll-subpage-tally' => 'Semak', |
| 4096 | + 'securepoll-tally-title' => 'Semak: $1', |
| 4097 | + 'securepoll-tally-not-finished' => 'Maaf, anda tidak dapat menyemak pemilihan sehingga selepas undian selesai.', |
| 4098 | + 'securepoll-can-decrypt' => 'Rekod pemilihan telah disulitkan, tetapi kunci penyulitan dapat diperoleh. |
| 4099 | +Anda boleh memilih untuk menyemak keputusan yang ada dalam pangkalan data, atau menyemak keputusan yang disulitkan daripada fail yang dimuat naik.', |
| 4100 | + 'securepoll-tally-no-key' => 'Anda tidak boleh menyemak pemilihan ini, kerana undian disulitkan, dan kunci penyulitan tidak dapat diperoleh.', |
| 4101 | + 'securepoll-tally-local-legend' => 'Semak keputusan tersimpan', |
| 4102 | + 'securepoll-tally-local-submit' => 'Cipta semakan', |
| 4103 | + 'securepoll-tally-upload-legend' => 'Muat naik longgakan bersulit', |
| 4104 | + 'securepoll-tally-upload-submit' => 'Cipta semakan', |
| 4105 | + 'securepoll-tally-error' => 'Ralat mentafsir rekod undian, tidak dapat menghasilkan semakan.', |
| 4106 | + 'securepoll-no-upload' => 'Tiada fail dimuat naik, tidak dapat menyemak keputusan.', |
3390 | 4107 | ); |
3391 | 4108 | |
| 4109 | +/** Maltese (Malti) |
| 4110 | + * @author Chrisportelli |
| 4111 | + */ |
| 4112 | +$messages['mt'] = array( |
| 4113 | + 'securepoll' => 'SecurePoll', |
| 4114 | + 'securepoll-desc' => 'Estensjoni għall-elezzjonijiet u s-sondaġġi', |
| 4115 | + 'securepoll-invalid-page' => 'Sottopaġna invalida "<nowiki>$1</nowiki>"', |
| 4116 | + 'securepoll-need-admin' => 'Trid tkun amministratur biex tesegwixxi din l-azzjoni.', |
| 4117 | + 'securepoll-too-few-params' => 'Parametri mhux biżżejjed tas-sottopaġna (ħolqa invalida)0.', |
| 4118 | + 'securepoll-invalid-election' => '"$1" mhijiex ID valida għall-elezzjoni.', |
| 4119 | + 'securepoll-welcome' => '<strong>Merħba $1!</strong>', |
| 4120 | + 'securepoll-not-started' => 'Din l-elezzjoni għadha ma bdietx. |
| 4121 | +Hi skedata li tibda nhar $2 fil-$3.', |
| 4122 | + 'securepoll-finished' => 'Din l-elezzjoni spiċċat, mhuwiex aktar possibbli li tivvota.', |
| 4123 | + 'securepoll-not-qualified' => "Ma tikwalifikax biex tivvota f'din l-elezzjoni: $1", |
| 4124 | + 'securepoll-change-disallowed' => "Diġà vvutajt f'din l-elezzjoni. |
| 4125 | +Mhuwiex possibbli li terġa' tivvota.", |
| 4126 | + 'securepoll-change-allowed' => "<strong>Nota: Inti diġà vvutajt f'din l-elezzjoni.</strong> |
| 4127 | +Tista' tbiddel il-vot tiegħek billi tibgħat il-formola t'hawn taħt. |
| 4128 | +Kun af li jekk tagħmel dan, il-vot oriġinali tiegħek jiġi skartat.", |
| 4129 | + 'securepoll-submit' => 'Ibgħat il-vot', |
| 4130 | + 'securepoll-gpg-receipt' => "Grazzi talli tajt l-vot tiegħek. |
| 4131 | + |
| 4132 | +Jekk tixtieq tista' żżomm ir-riċevuta segwenti bħala evidenza tal-vot tiegħek: |
| 4133 | + |
| 4134 | +<pre>$1</pre>", |
| 4135 | + 'securepoll-thanks' => 'Grazzi, il-vot tiegħek ġie reġistrat.', |
| 4136 | + 'securepoll-return' => "Erġa' lura lejn $1.", |
| 4137 | + 'securepoll-encrypt-error' => 'Impossibbli li l-voti tiegħek jiġi reġistrat. |
| 4138 | +Il-vot ma ġiex reġistrat! |
| 4139 | + |
| 4140 | +$1', |
| 4141 | + 'securepoll-no-gpg-home' => "Impossibbli toħloq id-direttorju tad-destinazzjoni ta' GPG.", |
| 4142 | + 'securepoll-secret-gpg-error' => "Żball waqt l-eżekuzzjoni ta' GPG. |
| 4143 | +Uża \$wgSecurePollShowErrorDetail=true; f'LocalSettings.php biex turi aktar dettalji.", |
| 4144 | + 'securepoll-full-gpg-error' => "Żball waqt l-eżekuzzjoni ta' GPG: |
| 4145 | + |
| 4146 | +Kmanda: $1 |
| 4147 | + |
| 4148 | +Żball: |
| 4149 | +<pre> $2 </pre>", |
| 4150 | + 'securepoll-gpg-config-error' => 'Iċ-ċwievet GPG ma ġew konfigurati sewwa.', |
| 4151 | + 'securepoll-gpg-parse-error' => "Żball fl-interpretazzjoni tar-riżultat ta' GPG.", |
| 4152 | + 'securepoll-no-decryption-key' => "L-ebda ċavetta ta' dekritazzjoni ma ġiet konfigurata. |
| 4153 | +Impossibbli li tiġi deċifrata.", |
| 4154 | + 'securepoll-jump' => 'Mur fis-server tal-votazzjoni', |
| 4155 | + 'securepoll-bad-ballot-submission' => 'Il-vot tiegħek kien invalidu: $1', |
| 4156 | + 'securepoll-unanswered-questions' => 'Trid tirrispondi kull mistoqsija.', |
| 4157 | + 'securepoll-remote-auth-error' => 'Żball waqt ir-ripristinaġġ mis-server tal-informazzjoni fuq il-kont tiegħek.', |
| 4158 | + 'securepoll-remote-parse-error' => "Żball fl-interpretazzjoni mis-server tar-risposta ta' awtorizzazzjoni.", |
| 4159 | + 'securepoll-api-invalid-params' => 'Parametri invalidi.', |
| 4160 | + 'securepoll-api-no-user' => 'L-ebda utent ma nstab bl-ID li ngħatat.', |
| 4161 | + 'securepoll-api-token-mismatch' => "It-token ta' sigurtà ma jaqbilx, ma tistax tidħol.", |
| 4162 | + 'securepoll-not-logged-in' => "Trid teffettwa l-login qabel ma tivvota f'din l-elezzjoni", |
| 4163 | + 'securepoll-too-few-edits' => "Jiddispjaċina, ma tistax tivvota. Trid tal-anqas tkun għamilt $1 {{PLURAL:$1|modifika|modifika}} biex tivvota f'din l-elezzjoni, inti għamilt $2.", |
| 4164 | + 'securepoll-blocked' => "Jiddispjaċina, ma tistax tivvota f'din l-elezzjoni jekk inti attwalment imblukkat milli timmodifika.", |
| 4165 | + 'securepoll-bot' => "Jiddispjaċina, il-kontijiet li għandhom l-istatus ta' bot ma jistgħux jivvutaw f'din l-elezzjoni.", |
| 4166 | + 'securepoll-not-in-group' => 'Il-membri biss tal-grupp "$1" jistgħu jivvutaw f\'din l-elezzjoni.', |
| 4167 | + 'securepoll-not-in-list' => "Jiddispjaċina, mintix fil-lista predeterminata tal-utenti awtorizzati li jivvutaw f'din l-elezzjoni.", |
| 4168 | + 'securepoll-list-title' => 'Lista tal-voti: $1', |
| 4169 | + 'securepoll-header-timestamp' => 'Ħin', |
| 4170 | + 'securepoll-header-voter-name' => 'Isem', |
| 4171 | + 'securepoll-header-voter-domain' => 'Dominju', |
| 4172 | + 'securepoll-header-ua' => 'Aġent tal-utent', |
| 4173 | + 'securepoll-header-cookie-dup' => 'Dup', |
| 4174 | + 'securepoll-header-strike' => 'Annulla', |
| 4175 | + 'securepoll-header-details' => 'Dettalji', |
| 4176 | + 'securepoll-strike-button' => 'Annulla dan il-vot', |
| 4177 | + 'securepoll-unstrike-button' => 'Neħħi l-annulament', |
| 4178 | + 'securepoll-strike-reason' => 'Raġuni:', |
| 4179 | + 'securepoll-strike-cancel' => 'Annulla', |
| 4180 | + 'securepoll-strike-error' => 'Żball waqt l-annulament jew ir-ripristinaġġ tal-vot: $1', |
| 4181 | + 'securepoll-details-link' => 'Dettalji', |
| 4182 | + 'securepoll-details-title' => 'Dettalji tal-vot: #$1', |
| 4183 | + 'securepoll-invalid-vote' => '"$1" mhijiex ID ta\' vot validu', |
| 4184 | + 'securepoll-header-voter-type' => "Tip ta' votant", |
| 4185 | + 'securepoll-voter-properties' => 'Proprjetajiet tal-votant', |
| 4186 | + 'securepoll-strike-log' => 'Reġistru tal-annulamenti', |
| 4187 | + 'securepoll-header-action' => 'Azzjoni', |
| 4188 | + 'securepoll-header-reason' => 'Raġuni', |
| 4189 | + 'securepoll-header-admin' => 'Amministratur', |
| 4190 | + 'securepoll-cookie-dup-list' => 'Utenti doppji skont il-cookie', |
| 4191 | + 'securepoll-dump-title' => 'Dump: $1', |
| 4192 | + 'securepoll-dump-no-crypt' => "Għal din l-elezzjoni mhi disponibbli l-ebda reġistrazzjoni kriptata, minħabba li l-elezzjoni mhix imposta li tuża' l-kritazzjoni.", |
| 4193 | + 'securepoll-dump-not-finished' => "Ir-reġistrazzjonijiet kriptati tal-elezzjoni huma disponibbli biss wara d-data ta' konklużjoni: $1 fil-$2", |
| 4194 | + 'securepoll-dump-no-urandom' => "Ma jistax jinfetaħ /dev/urandom. |
| 4195 | +Biex tinżamm il-privatezza tal-votant, ir-reġistrazzjonijieet kriptati tal-elezzjoni huma disponibbli pubblikament biss meta jistgħu jkunu mħawwda b'influss sigur ta' numru każwali.", |
| 4196 | + 'securepoll-translate-title' => 'Ittraduċi: $1', |
| 4197 | + 'securepoll-invalid-language' => 'Kodiċi tal-lingwa invalidu: "$1"', |
| 4198 | + 'securepoll-submit-translate' => 'Aġġorna', |
| 4199 | + 'securepoll-language-label' => 'Agħżel lingwa:', |
| 4200 | + 'securepoll-submit-select-lang' => 'Ittraduċi', |
| 4201 | + 'securepoll-header-title' => 'Isem', |
| 4202 | + 'securepoll-header-start-date' => 'Data tal-bidu', |
| 4203 | + 'securepoll-header-end-date' => 'Data tat-tmiem', |
| 4204 | + 'securepoll-subpage-vote' => 'Ivvota', |
| 4205 | + 'securepoll-subpage-translate' => 'Ittraduċi', |
| 4206 | + 'securepoll-subpage-list' => 'Elenka', |
| 4207 | + 'securepoll-subpage-dump' => 'Dump', |
| 4208 | + 'securepoll-subpage-tally' => 'Talja', |
| 4209 | + 'securepoll-tally-title' => 'Talja: $1', |
| 4210 | + 'securepoll-tally-not-finished' => 'Jiddispjaċina, ma tisgtħux tgħoddu r-riżultati tal-elezzjoni qabel mal-votazzjoni tispiċċa.', |
| 4211 | + 'securepoll-can-decrypt' => "Ir-reġistru tal-elezzjoni ġie kriptat, però ċ-ċavetta ta' dekritazzjoni hija disponibbli. |
| 4212 | +Inti tista' tagħżel jew li tgħodd ir-riżultati preżenti fid-databażi, jew li tgħodd ir-riżultati kriptati minn fajl imtella'.", |
| 4213 | + 'securepoll-tally-no-key' => 'Ma tistax tgħodd ir-riżultati tal-elezzjoni, minħabba li l-voti huma kriptati, u ċ-ċavetta tad-dekritazzjoni mhix disponibbli.', |
| 4214 | + 'securepoll-tally-local-legend' => 'L-għadd tar-riżultati salvati', |
| 4215 | + 'securepoll-tally-local-submit' => 'Oħloq talja', |
| 4216 | + 'securepoll-tally-upload-legend' => "Tella' riserva kriptata", |
| 4217 | + 'securepoll-tally-upload-submit' => 'Oħloq talja', |
| 4218 | + 'securepoll-tally-error' => 'Żball fl-interpretazzjoni tar-reġistrazzjoni tal-vot, ir-riżultati ma jistgħux jingħaddu.', |
| 4219 | + 'securepoll-no-upload' => "L-ebda fajl ma ġie mtella', ir-riżultati ma jistgħux jingħaddu.", |
| 4220 | +); |
| 4221 | + |
3392 | 4222 | /** Low German (Plattdüütsch) |
3393 | 4223 | * @author Slomox |
3394 | 4224 | */ |
— | — | @@ -3434,9 +4264,7 @@ |
3435 | 4265 | 'securepoll-no-decryption-key' => 'Keen Opslötel-Slötel instellt. |
3436 | 4266 | Opslöteln geiht nich.', |
3437 | 4267 | 'securepoll-jump' => 'Na’n Afstimmserver gahn', |
3438 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
3439 | | -Dien Stimm weer ungüllig: $1 |
3440 | | -</div>', |
| 4268 | + 'securepoll-bad-ballot-submission' => 'Dien Stimm weer ungüllig: $1', |
3441 | 4269 | 'securepoll-unanswered-questions' => 'Du musst all Fragen antern.', |
3442 | 4270 | 'securepoll-remote-auth-error' => 'Fehler bi’t Afropen vun dien Brukerkonteninfos vun’n Server.', |
3443 | 4271 | 'securepoll-remote-parse-error' => 'Fehler bi’t Interpreteren vun de Antwoord vun’n Server to de Rechten.', |
— | — | @@ -3562,6 +4390,10 @@ |
3563 | 4391 | 'securepoll-jump' => 'Naar de stemserver gaan', |
3564 | 4392 | 'securepoll-bad-ballot-submission' => 'Uw stem is ongeldig: $1', |
3565 | 4393 | 'securepoll-unanswered-questions' => 'U moet alle vragen beantwoorden.', |
| 4394 | + 'securepoll-invalid-rank' => 'Ongeldige rang. |
| 4395 | +U moet de kandidaten een rang geven tussen 1 en 999.', |
| 4396 | + 'securepoll-unranked-options' => 'Sommige stemmogelijkheden hebben geen rang. |
| 4397 | +U moet alle mogelijkheden een rang geven tussen 1 en 999.', |
3566 | 4398 | 'securepoll-remote-auth-error' => 'Er is een fout opgetreden bij het ophalen van uw gebruikersinformatie van de server.', |
3567 | 4399 | 'securepoll-remote-parse-error' => 'Er is een fout opgetreden bij het interpreteren van het antwoord van de server.', |
3568 | 4400 | 'securepoll-api-invalid-params' => 'Ongeldige parameters.', |
— | — | @@ -3588,6 +4420,7 @@ |
3589 | 4421 | 'securepoll-strike-reason' => 'Reden:', |
3590 | 4422 | 'securepoll-strike-cancel' => 'Annuleren', |
3591 | 4423 | 'securepoll-strike-error' => 'Er is een fout opgetreden bij het uitvoeren doorhalen/doorhalen ongedaan maken: $1', |
| 4424 | + 'securepoll-strike-token-mismatch' => 'De sessiegegevens zijn verloren gegaan.', |
3592 | 4425 | 'securepoll-details-link' => 'Details', |
3593 | 4426 | 'securepoll-details-title' => 'Stemdetails: #$1', |
3594 | 4427 | 'securepoll-invalid-vote' => '"$1" is geen geldig stemnummer', |
— | — | @@ -3603,6 +4436,8 @@ |
3604 | 4437 | 'securepoll-dump-not-finished' => 'De versleutelde stemgegevens zijn pas beschikbaar na het eindigen van de stemming op $1 om $2', |
3605 | 4438 | 'securepoll-dump-no-urandom' => 'Het was niet mogelijk om /dev/urandom te openen. |
3606 | 4439 | Om de privacy van de stemmers te beschermen, zijn de stemmingsgegevens pas beschikbaar als ze willekeurig gesorteerd kunnen worden met behulp van een willekeurige nummerreeks.', |
| 4440 | + 'securepoll-urandom-not-supported' => 'Deze server biedt geen ondersteuning voor het versleuteld aanmaken van willekeurige getallen. |
| 4441 | +Om de anonimiteit van stemmers te handhaven, zijn de versleutelde stemresultaten pas beschikbaar als ze zijn herordend via een veilige reeks van willekeurige getallen.', |
3607 | 4442 | 'securepoll-translate-title' => 'Vertalen: $1', |
3608 | 4443 | 'securepoll-invalid-language' => 'Ongeldige taalcode "$1"', |
3609 | 4444 | 'securepoll-submit-translate' => 'Bijwerken', |
— | — | @@ -3637,6 +4472,7 @@ |
3638 | 4473 | * @author Harald Khan |
3639 | 4474 | */ |
3640 | 4475 | $messages['nn'] = array( |
| 4476 | + 'securepoll' => 'TrygtVal', |
3641 | 4477 | 'securepoll-desc' => 'Ei utviding for val og undersøkingar', |
3642 | 4478 | 'securepoll-invalid-page' => 'Ugyldig underside «<nowiki>$1</nowiki>»', |
3643 | 4479 | 'securepoll-need-admin' => 'Du må vera ein administrator for å kunna utføra denne handlinga.', |
— | — | @@ -3676,25 +4512,44 @@ |
3677 | 4513 | 'securepoll-gpg-parse-error' => 'Feil ved tolking av utdata frå GPG.', |
3678 | 4514 | 'securepoll-no-decryption-key' => 'Ingen dekrypteringsnøkkel er sett opp. |
3679 | 4515 | Kan ikkje dekryptera.', |
| 4516 | + 'securepoll-jump' => 'Gå til stemmetenaren', |
| 4517 | + 'securepoll-bad-ballot-submission' => 'Di stemme var ugyldig: $1', |
3680 | 4518 | 'securepoll-unanswered-questions' => 'Du må svara på alle spørsmåla.', |
3681 | 4519 | 'securepoll-remote-auth-error' => 'Feil oppstod ved henting av kontoinformasjonen din frå filtenaren.', |
| 4520 | + 'securepoll-remote-parse-error' => 'Feil oppsto i samband med tolking av autorisasjonssvar frå tenaren', |
| 4521 | + 'securepoll-api-invalid-params' => 'Ugyldige parametrar.', |
3682 | 4522 | 'securepoll-api-no-user' => 'Ingen brukar var funnen med oppgjeven ID.', |
3683 | 4523 | 'securepoll-not-logged-in' => 'Du må vera innlogga for å kunna røysta i dette valet', |
| 4524 | + 'securepoll-too-few-edits' => 'Orsak, du kan ikkje røysta. Du lyt ha gjort minst {{PLURAL:$1|éi endring|$1 endringar}} for å kunna røysta ved dette valet. Du har gjort {{PLURAL:$2|éi|$2}}.', |
3684 | 4525 | 'securepoll-blocked' => 'Du kan diverre ikkje røysta i dette valet om du for tida er blokkert frå å gjera endringar', |
3685 | 4526 | 'securepoll-not-in-group' => 'Berre brukarar som er med i gruppa $1 kan røysta i denne avrøystinga.', |
3686 | 4527 | 'securepoll-not-in-list' => 'Du er diverre ikkje på lista over brukarar som har løyve til å røysta i denne avrøystinga.', |
| 4528 | + 'securepoll-list-title' => 'Vis stemmer: $1', |
3687 | 4529 | 'securepoll-header-timestamp' => 'Tid', |
3688 | 4530 | 'securepoll-header-voter-name' => 'Namn', |
3689 | 4531 | 'securepoll-header-voter-domain' => 'Domene', |
3690 | 4532 | 'securepoll-header-ua' => 'Brukaragent', |
| 4533 | + 'securepoll-header-cookie-dup' => 'Dublett', |
| 4534 | + 'securepoll-header-strike' => 'Stryk', |
3691 | 4535 | 'securepoll-header-details' => 'Opplysingar', |
| 4536 | + 'securepoll-strike-button' => 'Fjern', |
| 4537 | + 'securepoll-unstrike-button' => 'Opphev strykinga', |
3692 | 4538 | 'securepoll-strike-reason' => 'Grunngjeving:', |
| 4539 | + 'securepoll-strike-cancel' => 'Avbryt', |
| 4540 | + 'securepoll-strike-error' => 'Feil ved fjerning eller ved oppheving av fjerning: $1', |
3693 | 4541 | 'securepoll-details-link' => 'Detaljar', |
| 4542 | + 'securepoll-details-title' => 'Stemmedetaljar: #$1', |
3694 | 4543 | 'securepoll-invalid-vote' => '«$1» er ikkje ein gyldig røyst-ID', |
| 4544 | + 'securepoll-header-voter-type' => 'Stemmegjevartype', |
| 4545 | + 'securepoll-voter-properties' => 'Eigenskapar for røystaren', |
| 4546 | + 'securepoll-strike-log' => 'Strykingslogg', |
3695 | 4547 | 'securepoll-header-action' => 'Handling', |
3696 | 4548 | 'securepoll-header-reason' => 'Grunn', |
3697 | 4549 | 'securepoll-header-admin' => 'Administrator', |
| 4550 | + 'securepoll-cookie-dup-list' => 'Cookie duplikatbrukar', |
| 4551 | + 'securepoll-dump-title' => 'Dump: $1', |
3698 | 4552 | 'securepoll-dump-no-crypt' => 'Inga kryptert valregistrering er tilgjengeleg for dette valet, på grunn av at valet ikkje er sett opp til å nytta kryptering.', |
| 4553 | + 'securepoll-dump-not-finished' => 'Krypterte valregister er berre tilgjengelege etter avsluttinga den $1 klokka $2', |
3699 | 4554 | 'securepoll-translate-title' => 'Set om: $1', |
3700 | 4555 | 'securepoll-invalid-language' => 'Ugyldig språkode "$1"', |
3701 | 4556 | 'securepoll-submit-translate' => 'Oppdater', |
— | — | @@ -3706,11 +4561,21 @@ |
3707 | 4562 | 'securepoll-subpage-vote' => 'Stem', |
3708 | 4563 | 'securepoll-subpage-translate' => 'Set om', |
3709 | 4564 | 'securepoll-subpage-list' => 'Utslisting', |
| 4565 | + 'securepoll-subpage-dump' => 'Dump', |
| 4566 | + 'securepoll-subpage-tally' => 'Oppteljing', |
| 4567 | + 'securepoll-tally-title' => 'Oppteljing: $1', |
| 4568 | + 'securepoll-tally-not-finished' => 'Diverre, du kan ikkje telja opp valresultatet før valet er fullført.', |
| 4569 | + 'securepoll-can-decrypt' => 'Valregisteret har vorte kryptert, men dekrypteringsnøkkelen er tilgjengeleg. |
| 4570 | +Du kan velja å anten telja opp resultata tilgjengelege i databasen, eller å telja opp dei krypterte resultata frå ei opplasta fil.', |
| 4571 | + 'securepoll-tally-no-key' => 'Du kan ikkje telja opp dette valet fordi stemmene er krypterte og dekrypteringsnøkkelen er utilgjengeleg.', |
| 4572 | + 'securepoll-tally-upload-submit' => 'Opprett ei oppteljing', |
| 4573 | + 'securepoll-no-upload' => 'Ingen fil vart lasta opp, kan ikkje summera resultata.', |
3710 | 4574 | ); |
3711 | 4575 | |
3712 | 4576 | /** Norwegian (bokmål) (Norsk (bokmål)) |
3713 | 4577 | * @author Finnrind |
3714 | 4578 | * @author Guaca |
| 4579 | + * @author Jon Harald Søby |
3715 | 4580 | * @author Laaknor |
3716 | 4581 | * @author Nghtwlkr |
3717 | 4582 | * @author Stigmj |
— | — | @@ -3758,10 +4623,11 @@ |
3759 | 4624 | 'securepoll-no-decryption-key' => 'Ingen dekrypteringsnøkkel er konfigurert. |
3760 | 4625 | Kan ikke dekryptere.', |
3761 | 4626 | 'securepoll-jump' => 'Gå til stemmetjeneren', |
3762 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
3763 | | -Din stemme var ugyldig: $1 |
3764 | | -</div>', |
| 4627 | + 'securepoll-bad-ballot-submission' => 'Din stemme var ugyldig: $1', |
3765 | 4628 | 'securepoll-unanswered-questions' => 'Du må besvare alle spørsmålene.', |
| 4629 | + 'securepoll-invalid-rank' => 'Ugyldig rangering. Du må gi kandidatene en rangering mellom 1 og 999.', |
| 4630 | + 'securepoll-unranked-options' => 'Noen valg var urangerte. |
| 4631 | +Du må gi alle alternativene en rangering mellom 1 og 999.', |
3766 | 4632 | 'securepoll-remote-auth-error' => 'Feil oppsto ved henting av din kontoinformasjon fra tjeneren.', |
3767 | 4633 | 'securepoll-remote-parse-error' => 'Feil oppsto ved tolkning av autorisasjonssvar fra tjeneren.', |
3768 | 4634 | 'securepoll-api-invalid-params' => 'Ugyldige parametere.', |
— | — | @@ -3786,6 +4652,7 @@ |
3787 | 4653 | 'securepoll-strike-reason' => 'Årsak:', |
3788 | 4654 | 'securepoll-strike-cancel' => 'Avbryt', |
3789 | 4655 | 'securepoll-strike-error' => 'Feil ved fjerning eller ved opphevelse av fjerning: $1', |
| 4656 | + 'securepoll-strike-token-mismatch' => 'Sesjonsdata tapt', |
3790 | 4657 | 'securepoll-details-link' => 'Detaljer', |
3791 | 4658 | 'securepoll-details-title' => 'Stemmedetaljer: #$1', |
3792 | 4659 | 'securepoll-invalid-vote' => '«$1» er ikke en gyldig stemme-ID', |
— | — | @@ -3801,6 +4668,8 @@ |
3802 | 4669 | 'securepoll-dump-not-finished' => 'Krypterte valgregistre er kun tilgjengelige etter avsluttningen den $1 klokken $2', |
3803 | 4670 | 'securepoll-dump-no-urandom' => 'Kan ikke åpne /dev/urandom. |
3804 | 4671 | For å sikre en hemmelig avstemning er de krypterte valgregistrene kun offentlig tilgjengelig når de kan blandes med en sikker strøm av tilfeldige tall.', |
| 4672 | + 'securepoll-urandom-not-supported' => 'Denne tjeneren støtter ikke kryptografisk generering av tilfeldige tall. |
| 4673 | +For å opprettholde velgernes anonymitet vil de enkelte stemmene kun offentliggjøres når de kan anonymiseres med en generator for tilfeldige tall.', |
3805 | 4674 | 'securepoll-translate-title' => 'Oversett: $1', |
3806 | 4675 | 'securepoll-invalid-language' => 'Ugyldig språkkode «$1»', |
3807 | 4676 | 'securepoll-submit-translate' => 'Oppdater', |
— | — | @@ -3825,6 +4694,8 @@ |
3826 | 4695 | 'securepoll-tally-upload-submit' => 'Opprett en opptelling', |
3827 | 4696 | 'securepoll-tally-error' => 'Feil ved tolking av stemmeregisteret, kan ikke opprette en opptelling.', |
3828 | 4697 | 'securepoll-no-upload' => 'Ingen fil ble lastet opp, kan ikke summere opp resultatene.', |
| 4698 | + 'securepoll-dump-corrupt' => 'Dumpfila er ødelagt og kan ikke behandles.', |
| 4699 | + 'securepoll-tally-upload-error' => 'Feil ved opptelling av dumpfila: $1', |
3829 | 4700 | ); |
3830 | 4701 | |
3831 | 4702 | /** Occitan (Occitan) |
— | — | @@ -3875,6 +4746,9 @@ |
3876 | 4747 | 'securepoll-jump' => 'Anar al servidor de vòte', |
3877 | 4748 | 'securepoll-bad-ballot-submission' => 'Vòstre vòte es invalid : $1', |
3878 | 4749 | 'securepoll-unanswered-questions' => 'Vos cal respondre a totas las questions.', |
| 4750 | + 'securepoll-invalid-rank' => 'Reng invalid. Vos cal balhar als candidats un reng entre 1 e 999.', |
| 4751 | + 'securepoll-unranked-options' => "D'unas opcions an pas recebut de reng. |
| 4752 | +Vos cal balhar un reng entre 1 e 999 a totas las opcions.", |
3879 | 4753 | 'securepoll-remote-auth-error' => 'Error al moment de la recuperacion de las informacions de vòstre compte dempuèi lo servidor.', |
3880 | 4754 | 'securepoll-remote-parse-error' => 'Error al moment de l’interpretacion de la responsa d’autorizacion del servidor.', |
3881 | 4755 | 'securepoll-api-invalid-params' => 'Paramètres invalids.', |
— | — | @@ -3899,6 +4773,7 @@ |
3900 | 4774 | 'securepoll-strike-reason' => 'Rason :', |
3901 | 4775 | 'securepoll-strike-cancel' => 'Anullar', |
3902 | 4776 | 'securepoll-strike-error' => 'Error al moment del (des)raiatge : $1', |
| 4777 | + 'securepoll-strike-token-mismatch' => 'Pèrta de donadas de sesilha', |
3903 | 4778 | 'securepoll-details-link' => 'Detalhs', |
3904 | 4779 | 'securepoll-details-title' => 'Detalhs del vòte : #$1', |
3905 | 4780 | 'securepoll-invalid-vote' => '« $1 » es pas un ID de vòte valid', |
— | — | @@ -3914,6 +4789,8 @@ |
3915 | 4790 | 'securepoll-dump-not-finished' => "Las donadas criptadas son disponiblas solament aprèp la clausura de l'eleccion lo $1 a $2", |
3916 | 4791 | 'securepoll-dump-no-urandom' => 'Impossible de dobrir /dev/urandom. |
3917 | 4792 | Per manténer la confidencialitat dels votants, las donadas criptadas son disponiblas sonque se pòdon èsser reboladas amb un nombre de caractèrs aleatòris.', |
| 4793 | + 'securepoll-urandom-not-supported' => 'Aqueste servidor supòrta pas la generacion criptografica aleatòri de nombres. |
| 4794 | +Per assegurar la confidencialitat dels votants, las donadas criptadas son publicadas unicament quand pòdon trebolar un flus aleatòri de nombres.', |
3918 | 4795 | 'securepoll-translate-title' => 'Traduire : $1', |
3919 | 4796 | 'securepoll-invalid-language' => 'Còde de lenga « $1 » invalid.', |
3920 | 4797 | 'securepoll-submit-translate' => 'Metre a jorn', |
— | — | @@ -3938,6 +4815,8 @@ |
3939 | 4816 | 'securepoll-tally-upload-submit' => 'Crear un comptatge', |
3940 | 4817 | 'securepoll-tally-error' => "Error al moment de l'interpretacion dels enregistaments de vòte, impossible de produire un resultat.", |
3941 | 4818 | 'securepoll-no-upload' => 'Cap de fichièr es pas estat telecargat, impossible de comptar los resultats.', |
| 4819 | + 'securepoll-dump-corrupt' => 'Lo fichièr de salvament es corromput e pòt pas èsser utilizat.', |
| 4820 | + 'securepoll-tally-upload-error' => 'Error al moment del decargament del fichièr de salvament : $1', |
3942 | 4821 | ); |
3943 | 4822 | |
3944 | 4823 | /** Papiamento (Papiamentu) |
— | — | @@ -3986,9 +4865,7 @@ |
3987 | 4866 | 'securepoll-no-decryption-key' => 'No tin un klave deskriptivó konfigurá. |
3988 | 4867 | No por decrypt.', |
3989 | 4868 | 'securepoll-jump' => 'Bai na e server di votashon', |
3990 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
3991 | | -Bo voto no ta balido: $1 |
3992 | | -</div>', |
| 4869 | + 'securepoll-bad-ballot-submission' => 'Bo voto no ta balido: $1', |
3993 | 4870 | 'securepoll-unanswered-questions' => 'Bo mester kontestá tur e preguntanan.', |
3994 | 4871 | 'securepoll-remote-auth-error' => 'Tabatin problema na ora di buska informashonnan tokante di bo kuenta riba e server.', |
3995 | 4872 | 'securepoll-remote-parse-error' => 'Tabatin problema na ora di interpretá e derechinan for di riba e server.', |
— | — | @@ -4059,11 +4936,20 @@ |
4060 | 4937 | * @author Xqt |
4061 | 4938 | */ |
4062 | 4939 | $messages['pdc'] = array( |
| 4940 | + 'securepoll-welcome' => '<strong>Willkum $1!</strong>', |
| 4941 | + 'securepoll-return' => 'Zerick zu $1', |
4063 | 4942 | 'securepoll-header-timestamp' => 'Zeit', |
4064 | 4943 | 'securepoll-header-voter-name' => 'Naame', |
| 4944 | + 'securepoll-strike-reason' => 'Grund:', |
| 4945 | + 'securepoll-header-reason' => 'Grund', |
| 4946 | + 'securepoll-submit-select-lang' => 'Iwwersetze', |
| 4947 | + 'securepoll-header-title' => 'Naame', |
| 4948 | + 'securepoll-subpage-translate' => 'Iwwersetze', |
| 4949 | + 'securepoll-subpage-list' => 'Lischt', |
4065 | 4950 | ); |
4066 | 4951 | |
4067 | 4952 | /** Polish (Polski) |
| 4953 | + * @author Saper |
4068 | 4954 | * @author Sp5uhe |
4069 | 4955 | */ |
4070 | 4956 | $messages['pl'] = array( |
— | — | @@ -4109,15 +4995,13 @@ |
4110 | 4996 | 'securepoll-no-decryption-key' => 'Klucz odszyfrowujący nie został skonfigurowany. |
4111 | 4997 | Odszyfrowanie nie jest możliwe.', |
4112 | 4998 | 'securepoll-jump' => 'Przejdź do serwera obsługującego głosowanie', |
4113 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
4114 | | -Twój głos był nieważny – $1 |
4115 | | -</div>', |
| 4999 | + 'securepoll-bad-ballot-submission' => 'Twój głos był nieważny – $1', |
4116 | 5000 | 'securepoll-unanswered-questions' => 'Musisz odpowiedzieć na wszystkie pytania.', |
4117 | 5001 | 'securepoll-remote-auth-error' => 'Wystąpił błąd podczas pobierania informacji z serwera o Twoim koncie.', |
4118 | 5002 | 'securepoll-remote-parse-error' => 'Wystąpił błąd interpretacji odpowiedzi autoryzującej z serwera.', |
4119 | 5003 | 'securepoll-api-invalid-params' => 'Nieprawidłowe parametry.', |
4120 | 5004 | 'securepoll-api-no-user' => 'Nie znaleziono użytkownika o podanym ID.', |
4121 | | - 'securepoll-api-token-mismatch' => 'Niepwawidłowy żeton bezpieczeństwa, nie można się zalogować.', |
| 5005 | + 'securepoll-api-token-mismatch' => 'Nieprawidłowy żeton bezpieczeństwa, nie można się zalogować.', |
4122 | 5006 | 'securepoll-not-logged-in' => 'Musisz się zalogować, aby głosować w tych wyborach', |
4123 | 5007 | 'securepoll-too-few-edits' => 'Niestety, nie możesz głosować. Musisz mieć przynajmniej $1 {{PLURAL:$1|edycję|edycje|edycji}} aby głosować w tych wyborach, wykonane $2.', |
4124 | 5008 | 'securepoll-blocked' => 'Niestety, nie możesz głosować w tych wyborach, ponieważ masz zablokowaną możliwość edytowania.', |
— | — | @@ -4137,6 +5021,7 @@ |
4138 | 5022 | 'securepoll-strike-reason' => 'Powód', |
4139 | 5023 | 'securepoll-strike-cancel' => 'Zrezygnuj', |
4140 | 5024 | 'securepoll-strike-error' => 'Błąd podczas skreślania lub usuwania skreślenia – $1', |
| 5025 | + 'securepoll-strike-token-mismatch' => 'Sesja użytkownika została utracona', |
4141 | 5026 | 'securepoll-details-link' => 'Szczegóły', |
4142 | 5027 | 'securepoll-details-title' => 'Szczegóły głosu nr $1', |
4143 | 5028 | 'securepoll-invalid-vote' => '„$1” nie jest poprawnym identyfikatorem głosu', |
— | — | @@ -4152,6 +5037,8 @@ |
4153 | 5038 | 'securepoll-dump-not-finished' => 'Zaszyfrowane rekordy głosów dostępne będą dopiero po zakończeniu wyborów $1 o $2', |
4154 | 5039 | 'securepoll-dump-no-urandom' => 'Nie można otworzyć /dev/urandom. |
4155 | 5040 | Dla zapewnienia wyborcom poufności, zaszyfrowane rekordy głosów są publicznie dostępne wyłącznie wymieszane z danymi losowymi.', |
| 5041 | + 'securepoll-urandom-not-supported' => 'System operacyjny na serwerze nie pozwala na korzystanie z urządzenia do tworzenia liczb losowych spełniających wymagania kryptografii. |
| 5042 | +Dla zapewnienia wyborcom poufności, zaszyfrowane rekordy głosów są publicznie dostępne wyłącznie wymieszane z danymi losowymi.', |
4156 | 5043 | 'securepoll-translate-title' => 'Tłumaczenie $1', |
4157 | 5044 | 'securepoll-invalid-language' => 'Nieprawidłowy kod języka „$1”', |
4158 | 5045 | 'securepoll-submit-translate' => 'Uaktualnij', |
— | — | @@ -4166,7 +5053,7 @@ |
4167 | 5054 | 'securepoll-subpage-dump' => 'Zrzut', |
4168 | 5055 | 'securepoll-subpage-tally' => 'Rejestr', |
4169 | 5056 | 'securepoll-tally-title' => 'Rejestr $1', |
4170 | | - 'securepoll-tally-not-finished' => 'Nie można podliczyć głosów, przed zakończeniem wyborów.', |
| 5057 | + 'securepoll-tally-not-finished' => 'Nie można podliczać głosów dopóki wybory trwają.', |
4171 | 5058 | 'securepoll-can-decrypt' => 'Rekord głosu został zaszyfrowany, ale klucz odszyfrowujący jest dostępny. |
4172 | 5059 | Można podliczyć wyniki obecne w bazie danych lub podliczyć wyniki z przesłanego zaszyfrowanego pliku.', |
4173 | 5060 | 'securepoll-tally-no-key' => 'Nie możesz podliczyć wyniku wyborów, ponieważ głosy są zaszyfrowane, a klucz odszyfrowujący jest niedostępny.', |
— | — | @@ -4176,9 +5063,125 @@ |
4177 | 5064 | 'securepoll-tally-upload-submit' => 'Utwórz rejestr', |
4178 | 5065 | 'securepoll-tally-error' => 'Błąd interpretacji rekordu głosu, nie można wykonać podliczenia.', |
4179 | 5066 | 'securepoll-no-upload' => 'Żaden plik nie został przesłany, nie można podliczyć głosów.', |
| 5067 | + 'securepoll-dump-corrupt' => 'Plik ze zrzutem danych jest uszkodzony i nie być przetworzony.', |
| 5068 | + 'securepoll-tally-upload-error' => 'Podczas podliczania pliku ze zrzutem danych wystąpił błąd: $1', |
4180 | 5069 | ); |
4181 | 5070 | |
| 5071 | +/** Piedmontese (Piemontèis) |
| 5072 | + * @author Dragonòt |
| 5073 | + */ |
| 5074 | +$messages['pms'] = array( |
| 5075 | + 'securepoll' => 'SecurePoll', |
| 5076 | + 'securepoll-desc' => 'Estension për elession e arserche', |
| 5077 | + 'securepoll-invalid-page' => 'Sotpàgina nen vàlida "<nowiki>$1</nowiki>"', |
| 5078 | + 'securepoll-need-admin' => "It deuve esse aministrador për fé st'assion-sì", |
| 5079 | + 'securepoll-too-few-params' => 'Ij paràmetr ëd la sotpàgina a basto pa (anliura nen vàlida)', |
| 5080 | + 'securepoll-invalid-election' => '"$1" a l\'é pa n\'ID vàlid për l\'elession', |
| 5081 | + 'securepoll-welcome' => '<strong>Bin ëvnù $1!</strong>', |
| 5082 | + 'securepoll-not-started' => "St'elession-sì a l'é ancó pa partìa. |
| 5083 | +A l'é programà për parte ël $2 a $3.", |
| 5084 | + 'securepoll-finished' => "St'elession-sì a l'é finìa, it peule pa pì voté.", |
| 5085 | + 'securepoll-not-qualified' => "It ses pa qualifià për voté an st'elession-sì: $1", |
| 5086 | + 'securepoll-change-disallowed' => "It l'has già votà an st'elession-sì. |
| 5087 | +It peule pa torna voté.", |
| 5088 | + 'securepoll-change-allowed' => "<strong>Nòta: it l'has già votà an st'elession-sì.</strong> |
| 5089 | +It peule cambié tò vot an compiland la form sota. |
| 5090 | +Nòta che s'it faras sòn-sì, tò vot original a sarà scartà.", |
| 5091 | + 'securepoll-submit' => 'Spediss ël vot', |
| 5092 | + 'securepoll-gpg-receipt' => "Mersì për avèj votà. |
| 5093 | + |
| 5094 | +S'it veule, it peule conservé l'arseivuda sota com evidensa ëd tò vot: |
| 5095 | + |
| 5096 | +<pre>$1</pre>", |
| 5097 | + 'securepoll-thanks' => "Mersì, tò vot a l'é stàit registrà.", |
| 5098 | + 'securepoll-return' => 'Torna a $1', |
| 5099 | + 'securepoll-encrypt-error' => "Eror an cifrand le anformassion dël vot. |
| 5100 | +Tò vot a l'é pa stàit memorisà! |
| 5101 | + |
| 5102 | +$1", |
| 5103 | + 'securepoll-no-gpg-home' => 'Ampossìbil creé la directory prinsipal ëd GPG.', |
| 5104 | + 'securepoll-secret-gpg-error' => 'Eror fasend giré GPG. |
| 5105 | +Dòvra $wgSecurePollShowErrorDetail=true; an LocalSettings.php për mosté pì ëd detaj.', |
| 5106 | + 'securepoll-full-gpg-error' => 'Eror fasend giré GPG: |
| 5107 | + |
| 5108 | +Comand: $1 |
| 5109 | + |
| 5110 | +Eror: |
| 5111 | +<pre>$2</pre>', |
| 5112 | + 'securepoll-gpg-config-error' => 'Le ciav GPG a son configurà nen giuste.', |
| 5113 | + 'securepoll-gpg-parse-error' => "Eror an antërpretand l'output ëd GPG.", |
| 5114 | + 'securepoll-no-decryption-key' => 'Pa gnun-e ciav ëd decifrassion a son configurà. |
| 5115 | +As peul pa decifré.', |
| 5116 | + 'securepoll-jump' => 'Va al server ëd la votassion', |
| 5117 | + 'securepoll-bad-ballot-submission' => "Tò vot a l'era pa vàlid: $1", |
| 5118 | + 'securepoll-unanswered-questions' => 'It deuve arsponde a tute le custion.', |
| 5119 | + 'securepoll-remote-auth-error' => 'Eror an lesend le anformassion ëd tò cont dal server.', |
| 5120 | + 'securepoll-remote-parse-error' => "Eror an antërpretand l'arspòsta d'autorisassion dal server.", |
| 5121 | + 'securepoll-api-invalid-params' => 'Paràmetr pa vàlid.', |
| 5122 | + 'securepoll-api-no-user' => "Pa gnun utent trovà con l'ID fornì.", |
| 5123 | + 'securepoll-api-token-mismatch' => 'Ij token ëd sicurëssa a corispondo pa, it peule pa intré.', |
| 5124 | + 'securepoll-not-logged-in' => "It deuve intré për voté an st'elession-sì", |
| 5125 | + 'securepoll-too-few-edits' => "Spiasent, it peule pa voté. It deuve avèj fàit almanch $1 {{PLURAL:$1|modìfica|modìfiche}} për voté an st'elession-sì, ti it l'has fane $2.", |
| 5126 | + 'securepoll-blocked' => "Spiasent, it peule pa voté an st'elession-sì se it ses blocà.", |
| 5127 | + 'securepoll-bot' => "Spiasent, ij cont lë stat ëd bot a peulo pa voté an st'elession-sì.", |
| 5128 | + 'securepoll-not-in-group' => 'Mach ij mèmber dël grup "$1" a peulo voté an st\'elession-sì.', |
| 5129 | + 'securepoll-not-in-list' => "Spiasent, it ses pa ant la lista predeterminà d'utent autorisà a voté an st'elession-sì.", |
| 5130 | + 'securepoll-list-title' => 'Lista dij vot: $1', |
| 5131 | + 'securepoll-header-timestamp' => 'Ora', |
| 5132 | + 'securepoll-header-voter-name' => 'Nòm', |
| 5133 | + 'securepoll-header-voter-domain' => 'Domini', |
| 5134 | + 'securepoll-header-ua' => 'Agent utent', |
| 5135 | + 'securepoll-header-cookie-dup' => 'Duplicà', |
| 5136 | + 'securepoll-header-strike' => 'Anulà', |
| 5137 | + 'securepoll-header-details' => 'Detaj', |
| 5138 | + 'securepoll-strike-button' => 'Anulà', |
| 5139 | + 'securepoll-unstrike-button' => 'Scansela anulament', |
| 5140 | + 'securepoll-strike-reason' => 'Rason:', |
| 5141 | + 'securepoll-strike-cancel' => 'Scancela', |
| 5142 | + 'securepoll-strike-error' => 'Eror an fasend anula/scansela anulament: $1', |
| 5143 | + 'securepoll-details-link' => 'Detaj', |
| 5144 | + 'securepoll-details-title' => 'Detaj dël vot: #$1', |
| 5145 | + 'securepoll-invalid-vote' => '"$1" a l\'é pa l\'ID d\'un vot vàlid', |
| 5146 | + 'securepoll-header-voter-type' => 'Rasa ëd votant', |
| 5147 | + 'securepoll-voter-properties' => 'Proprietà dël votant', |
| 5148 | + 'securepoll-strike-log' => "Registr ëd j'anulament", |
| 5149 | + 'securepoll-header-action' => 'Assion', |
| 5150 | + 'securepoll-header-reason' => 'Rason', |
| 5151 | + 'securepoll-header-admin' => 'Aministrador', |
| 5152 | + 'securepoll-cookie-dup-list' => 'Utent dobi për cookie', |
| 5153 | + 'securepoll-dump-title' => 'Dump: $1', |
| 5154 | + 'securepoll-dump-no-crypt' => "Pa gnun-e registrassion cifrà dl'elession a-i son për st'elession-sì, përchè l'elession a l'é pa configurà për dovré la cifradura.", |
| 5155 | + 'securepoll-dump-not-finished' => "Le registrassion cifrà dl'elession a son mach disponìbij d'apress la data ëd fin ël $1 a $2", |
| 5156 | + 'securepoll-dump-no-urandom' => "As peul pa deurbe /dev/urandom. |
| 5157 | +Për manten-e la privacy dij votant, le registrassion cifrà dl'elession a saran disponibij publicament mach quand a saran cifrà con un fluss sicur ëd nùmer casuaj.", |
| 5158 | + 'securepoll-translate-title' => 'Traduv: $1', |
| 5159 | + 'securepoll-invalid-language' => 'Còdes lenga pa vàlid "$1"', |
| 5160 | + 'securepoll-submit-translate' => 'Agiorna', |
| 5161 | + 'securepoll-language-label' => 'Sern lenga:', |
| 5162 | + 'securepoll-submit-select-lang' => 'Traduv', |
| 5163 | + 'securepoll-header-title' => 'Nòm', |
| 5164 | + 'securepoll-header-start-date' => 'Data inissi', |
| 5165 | + 'securepoll-header-end-date' => 'Data fin', |
| 5166 | + 'securepoll-subpage-vote' => 'Vòta', |
| 5167 | + 'securepoll-subpage-translate' => 'Traduv', |
| 5168 | + 'securepoll-subpage-list' => 'Lista', |
| 5169 | + 'securepoll-subpage-dump' => 'Dump', |
| 5170 | + 'securepoll-subpage-tally' => 'Puntegi', |
| 5171 | + 'securepoll-tally-title' => 'Puntegi: $1', |
| 5172 | + 'securepoll-tally-not-finished' => "Spiasent, it peule pa contegé l'elession fin a che ël vot a sia nen complet.", |
| 5173 | + 'securepoll-can-decrypt' => "La registrassion ëd l'elession a l'é stàita cifrà, ma la ciav ëd decifrassion a l'é disponìbila. |
| 5174 | +It peule serne sia ëd conté j'arzultà present ant ël database, sia ëd conté j'arzultà cifrà da un file carià.", |
| 5175 | + 'securepoll-tally-no-key' => "It peule pa conté st'elession-sì, përchè ij vot a son cifrà, e la ciav ëd decifrassion a l'é pa disponìbil.", |
| 5176 | + 'securepoll-tally-local-legend' => "Conta j'arzultà memorisà", |
| 5177 | + 'securepoll-tally-local-submit' => 'Crea ël contegi', |
| 5178 | + 'securepoll-tally-upload-legend' => 'Caria ël dump cifrà', |
| 5179 | + 'securepoll-tally-upload-submit' => 'Crea ël contegi', |
| 5180 | + 'securepoll-tally-error' => 'Eror an antërpretand la registrassion dij vot, a peul pa prodove un contegi.', |
| 5181 | + 'securepoll-no-upload' => "pa gnun file a l'é stàit carià, as peul pa conté j'arzultà.", |
| 5182 | +); |
| 5183 | + |
4182 | 5184 | /** Portuguese (Português) |
| 5185 | + * @author Everton137 |
4183 | 5186 | * @author Lijealso |
4184 | 5187 | * @author Malafaya |
4185 | 5188 | * @author Waldir |
— | — | @@ -4226,10 +5229,11 @@ |
4227 | 5230 | 'securepoll-no-decryption-key' => 'Nenhuma chave de descodificação está configurada. |
4228 | 5231 | Não é possível descodificar.', |
4229 | 5232 | 'securepoll-jump' => 'Ir para o servidor de votação', |
4230 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
4231 | | -O seu voto foi inválido: $1 |
4232 | | -</div>', |
| 5233 | + 'securepoll-bad-ballot-submission' => 'O seu voto foi inválido: $1', |
4233 | 5234 | 'securepoll-unanswered-questions' => 'Você deve responder todas as perguntas.', |
| 5235 | + 'securepoll-invalid-rank' => 'Ranque inválido. Você deve fornecer aos candidatos um ranque entre 1 e 999.', |
| 5236 | + 'securepoll-unranked-options' => 'Algumas opções não foram ranqueadas. |
| 5237 | +Você deve fornecer para todas opções um ranque entre 1 e 999.', |
4234 | 5238 | 'securepoll-remote-auth-error' => 'Erro ao buscar as informações da sua conta a partir do servidor.', |
4235 | 5239 | 'securepoll-remote-parse-error' => 'Erro ao interpretar a resposta de autorização do servidor.', |
4236 | 5240 | 'securepoll-api-invalid-params' => 'Parâmetros inválidos.', |
— | — | @@ -4246,7 +5250,7 @@ |
4247 | 5251 | 'securepoll-header-voter-name' => 'Nome', |
4248 | 5252 | 'securepoll-header-voter-domain' => 'Domínio', |
4249 | 5253 | 'securepoll-header-ua' => 'Agente de utilizador', |
4250 | | - 'securepoll-header-cookie-dup' => 'Dup', |
| 5254 | + 'securepoll-header-cookie-dup' => 'Duplicado', |
4251 | 5255 | 'securepoll-header-strike' => 'Riscar', |
4252 | 5256 | 'securepoll-header-details' => 'Detalhes', |
4253 | 5257 | 'securepoll-strike-button' => 'Riscar', |
— | — | @@ -4254,6 +5258,7 @@ |
4255 | 5259 | 'securepoll-strike-reason' => 'Motivo:', |
4256 | 5260 | 'securepoll-strike-cancel' => 'Cancelar', |
4257 | 5261 | 'securepoll-strike-error' => 'Erro ao riscar/remover risco: $1', |
| 5262 | + 'securepoll-strike-token-mismatch' => 'Dados da sessão perdidos.', |
4258 | 5263 | 'securepoll-details-link' => 'Detalhes', |
4259 | 5264 | 'securepoll-details-title' => 'Detalhes do voto: #$1', |
4260 | 5265 | 'securepoll-invalid-vote' => '"$1" não é um ID de voto válido', |
— | — | @@ -4293,10 +5298,12 @@ |
4294 | 5299 | 'securepoll-tally-upload-submit' => 'Criar apuramento', |
4295 | 5300 | 'securepoll-tally-error' => 'Erro na interpretação de registo de voto, não é possível produzir apuramento.', |
4296 | 5301 | 'securepoll-no-upload' => 'Nenhum ficheiro foi carregado, não é possível apurar resultados.', |
| 5302 | + 'securepoll-dump-corrupt' => 'O arquivo dump está corrompido e não pode ser processado.', |
4297 | 5303 | ); |
4298 | 5304 | |
4299 | 5305 | /** Brazilian Portuguese (Português do Brasil) |
4300 | 5306 | * @author Eduardo.mps |
| 5307 | + * @author Everton137 |
4301 | 5308 | * @author GKnedo |
4302 | 5309 | * @author Heldergeovane |
4303 | 5310 | */ |
— | — | @@ -4343,9 +5350,7 @@ |
4344 | 5351 | 'securepoll-no-decryption-key' => 'Nenhuma chave de descriptografia está configurada. |
4345 | 5352 | Não foi possível descriptografar.', |
4346 | 5353 | 'securepoll-jump' => 'Ir para o servidor de votação', |
4347 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
4348 | | -Seu voto foi inválido: $1 |
4349 | | -</div>', |
| 5354 | + 'securepoll-bad-ballot-submission' => 'Seu voto foi inválido: $1', |
4350 | 5355 | 'securepoll-unanswered-questions' => 'Você deve responder todas as questões.', |
4351 | 5356 | 'securepoll-remote-auth-error' => 'Erro ao tentar obter suas informações de conta do servidor.', |
4352 | 5357 | 'securepoll-remote-parse-error' => 'Erro ao interpretar a resposta de autorização do servidor.', |
— | — | @@ -4410,15 +5415,17 @@ |
4411 | 5416 | 'securepoll-tally-upload-submit' => 'Criar contagem de votos', |
4412 | 5417 | 'securepoll-tally-error' => 'Erro ao interpretar registro de votos, não foi possível produzir uma contagem.', |
4413 | 5418 | 'securepoll-no-upload' => 'Nenhum arquivo foi carregado, não foi possível contar os votos para o resultado.', |
| 5419 | + 'securepoll-ranks' => 'Ranque final.', |
4414 | 5420 | ); |
4415 | 5421 | |
4416 | 5422 | /** Romanian (Română) |
| 5423 | + * @author Firilacroco |
4417 | 5424 | * @author Mihai |
4418 | 5425 | */ |
4419 | 5426 | $messages['ro'] = array( |
4420 | 5427 | 'securepoll-submit' => 'Trimite votul', |
4421 | 5428 | 'securepoll-unanswered-questions' => 'Trebuie să răspunzi la toate întrebările.', |
4422 | | - 'securepoll-api-invalid-params' => 'Parametri invalizi.', |
| 5429 | + 'securepoll-api-invalid-params' => 'Parametri incorecţi.', |
4423 | 5430 | 'securepoll-api-no-user' => 'Niciun utilizator cu acest ID nu a fost găsit.', |
4424 | 5431 | 'securepoll-list-title' => 'Listă voturi: $1', |
4425 | 5432 | 'securepoll-header-voter-name' => 'Nume', |
— | — | @@ -4503,6 +5510,9 @@ |
4504 | 5511 | 'securepoll-jump' => 'Перейти на сервер голосований', |
4505 | 5512 | 'securepoll-bad-ballot-submission' => 'Ваш голос не действителен: $1', |
4506 | 5513 | 'securepoll-unanswered-questions' => 'Вы должны ответить на все вопросы.', |
| 5514 | + 'securepoll-invalid-rank' => 'Недействительный ранг. Вы должны указать для кандидата ранг от 1 до 999.', |
| 5515 | + 'securepoll-unranked-options' => 'Некоторые записи не проранжированы. |
| 5516 | +Вам необходимо указать ранг от 1 до 999 для всех записей.', |
4507 | 5517 | 'securepoll-remote-auth-error' => 'Ошибка получения информации об учётной записи с сервера.', |
4508 | 5518 | 'securepoll-remote-parse-error' => 'Ошибка интерпретации ответа авторизации с сервера.', |
4509 | 5519 | 'securepoll-api-invalid-params' => 'Ошибочные параметры.', |
— | — | @@ -4527,6 +5537,7 @@ |
4528 | 5538 | 'securepoll-strike-reason' => 'Причина:', |
4529 | 5539 | 'securepoll-strike-cancel' => 'Отмена', |
4530 | 5540 | 'securepoll-strike-error' => 'Ошибка при вычёркивании или снятии вычёркивания: $1', |
| 5541 | + 'securepoll-strike-token-mismatch' => 'Потеря данных сессии', |
4531 | 5542 | 'securepoll-details-link' => 'Подробности', |
4532 | 5543 | 'securepoll-details-title' => 'Подробности голосования: #$1', |
4533 | 5544 | 'securepoll-invalid-vote' => '«$1» не является допустимым идентификатором голосования', |
— | — | @@ -4542,6 +5553,8 @@ |
4543 | 5554 | 'securepoll-dump-not-finished' => 'Зашифрованные записи подачи голосов доступны только после окончания голосования $1 $2', |
4544 | 5555 | 'securepoll-dump-no-urandom' => 'Не удаётся открыть /dev/urandom. |
4545 | 5556 | Для обеспечения конфиденциальности избирателей, зашифрованные записи подачи голосов можно делать общедоступными, когда порядок их следования изменён с использованием безопасного источника случайных чисел.', |
| 5557 | + 'securepoll-urandom-not-supported' => 'Этот сервер не поддерживает криптографические генерирование случайных чисел. |
| 5558 | +Чтобы сохранить конфиденциальность голосующих, закодированные записи голосования станут общедоступными только после того, как они смогут быть перемешаны безопасным потоком случайных чисел.', |
4546 | 5559 | 'securepoll-translate-title' => 'Перевод: $1', |
4547 | 5560 | 'securepoll-invalid-language' => 'Ошибочный код языка «$1»', |
4548 | 5561 | 'securepoll-submit-translate' => 'Обновить', |
— | — | @@ -4566,6 +5579,8 @@ |
4567 | 5580 | 'securepoll-tally-upload-submit' => 'Произвести подсчёт', |
4568 | 5581 | 'securepoll-tally-error' => 'Ошибка интерпретации записи голоса, невозможно произвести подсчёт.', |
4569 | 5582 | 'securepoll-no-upload' => 'Файл не был загружен, невозможно подсчитать результаты.', |
| 5583 | + 'securepoll-dump-corrupt' => 'Файл дампа повреждён и не может быть обработан.', |
| 5584 | + 'securepoll-tally-upload-error' => 'Ошибка согласованности файла дампа: $1', |
4570 | 5585 | ); |
4571 | 5586 | |
4572 | 5587 | /** Yakut (Саха тыла) |
— | — | @@ -4614,9 +5629,7 @@ |
4615 | 5630 | 'securepoll-no-decryption-key' => 'Расшифровка күлүүһэ настройкаламматах. |
4616 | 5631 | Расшифровкалыыр табыллыбат.', |
4617 | 5632 | 'securepoll-jump' => 'Куоластааһын сиэрбэригэр көһүү', |
4618 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
4619 | | -Эн куолаһыҥ ааҕыллыбат: $1 |
4620 | | -</div>', |
| 5633 | + 'securepoll-bad-ballot-submission' => 'Эн куолаһыҥ ааҕыллыбат: $1', |
4621 | 5634 | 'securepoll-unanswered-questions' => 'Бары ыйытыыларга хоруйдуохтааххын.', |
4622 | 5635 | 'securepoll-remote-auth-error' => 'Аат-суол туһунан сибидиэнньэлэри сиэрбэртэн ылыыга алҕас таҕыста.', |
4623 | 5636 | 'securepoll-remote-parse-error' => 'Сиэрбэртэн авторизацияны сыыһа көрүү буолбутун туһунан хоруй кэллэ.', |
— | — | @@ -4739,6 +5752,9 @@ |
4740 | 5753 | 'securepoll-jump' => 'Prejsť na hlasovací server', |
4741 | 5754 | 'securepoll-bad-ballot-submission' => 'Váš hlas bol neplatný: $1', |
4742 | 5755 | 'securepoll-unanswered-questions' => 'Musíte zodpovedať všetky otázky.', |
| 5756 | + 'securepoll-invalid-rank' => 'Neplatné hodnotenie. Musíte zadať kandidátov s hodnotením medzi 1 a 999.', |
| 5757 | + 'securepoll-unranked-options' => 'Niektoré možnosti neboli ohodnotené. |
| 5758 | +Musíte dať každej možnosti hodnotenie medzi 1 a 999.', |
4743 | 5759 | 'securepoll-remote-auth-error' => 'Pri zisťovaní vašich prihlasovacích informácií zo servera nastala chyba.', |
4744 | 5760 | 'securepoll-remote-parse-error' => 'Pri interpretácii odpovede o autorizácii od servera nastala chyba.', |
4745 | 5761 | 'securepoll-api-invalid-params' => 'Neplatné parametre.', |
— | — | @@ -4763,6 +5779,7 @@ |
4764 | 5780 | 'securepoll-strike-reason' => 'Dôvod:', |
4765 | 5781 | 'securepoll-strike-cancel' => 'Zrušiť', |
4766 | 5782 | 'securepoll-strike-error' => 'Chyba operácie škrtnutie/zrušenie škrtnutia: $1', |
| 5783 | + 'securepoll-strike-token-mismatch' => 'Údaje o relácii boli stratené', |
4767 | 5784 | 'securepoll-details-link' => 'Podrobnosti', |
4768 | 5785 | 'securepoll-details-title' => 'Podrobnosti hlasovania: #$1', |
4769 | 5786 | 'securepoll-invalid-vote' => '„$1“ nie je platný ID hlasovania', |
— | — | @@ -4778,6 +5795,8 @@ |
4779 | 5796 | 'securepoll-dump-not-finished' => 'Šifrované záznamy o voľbách sú dostupné len po dátume ich skončenia: $1 $2', |
4780 | 5797 | 'securepoll-dump-no-urandom' => 'Nie je možné otvoriť /dev/urandom. |
4781 | 5798 | Aby bola zabezpečená anonymita hlasujúceho, šifrované záznamy o voľbách sú dostupné verejne len keď bôžu byť zamiešané náhodným tokom čísel.', |
| 5799 | + 'securepoll-urandom-not-supported' => 'Tento server nepodporuje tvorbu kryptograficky náhodných čísiel. |
| 5800 | +Aby sa zachovalo súkromie hlasujúcich, šifrovaný záznam o voľbách je verejne dostupný iba keď ho možno kryptograficky zabezpečiť tokom náhodných čísiel.', |
4782 | 5801 | 'securepoll-translate-title' => 'Preložiť: $1', |
4783 | 5802 | 'securepoll-invalid-language' => 'Neplatný kód jazyka „$1“', |
4784 | 5803 | 'securepoll-submit-translate' => 'Aktualizovať', |
— | — | @@ -4802,6 +5821,11 @@ |
4803 | 5822 | 'securepoll-tally-upload-submit' => 'Vytvoriť vyhodnotenie', |
4804 | 5823 | 'securepoll-tally-error' => 'Chyba pri interpretácii záznamu o hlasovaní, nemožno vyhodnotiť hlasovanie.', |
4805 | 5824 | 'securepoll-no-upload' => 'Nebol nahraný súbor, nemožno vyhodnotiť hlasovanie.', |
| 5825 | + 'securepoll-dump-corrupt' => 'Súbor s výpisom je poškodený a nemožno ho spracovať.', |
| 5826 | + 'securepoll-tally-upload-error' => 'Chyba pri kontrole súboru výpisu: $1', |
| 5827 | + 'securepoll-pairwise-victories' => 'Párová matica víťazstiev', |
| 5828 | + 'securepoll-strength-matrix' => 'Párová matica sily', |
| 5829 | + 'securepoll-ranks' => 'Finálne hodnotenie', |
4806 | 5830 | ); |
4807 | 5831 | |
4808 | 5832 | /** Serbian Cyrillic ekavian (ћирилица) |
— | — | @@ -4812,10 +5836,12 @@ |
4813 | 5837 | ); |
4814 | 5838 | |
4815 | 5839 | /** Swedish (Svenska) |
| 5840 | + * @author Fluff |
4816 | 5841 | * @author Gabbe.g |
4817 | 5842 | * @author Micke |
4818 | 5843 | * @author Najami |
4819 | 5844 | * @author Poxnar |
| 5845 | + * @author StefanB |
4820 | 5846 | */ |
4821 | 5847 | $messages['sv'] = array( |
4822 | 5848 | 'securepoll' => 'SäkerOmröstning', |
— | — | @@ -4829,7 +5855,7 @@ |
4830 | 5856 | Den planeras starta den $2 kl $3.', |
4831 | 5857 | 'securepoll-finished' => 'Valet är avslutat, så du kan inte längre rösta.', |
4832 | 5858 | 'securepoll-not-qualified' => 'Du är inte kvalificerad att rösta i den här omröstningen: $1', |
4833 | | - 'securepoll-change-disallowed' => 'Du har redan röstat i den här omröstningen. |
| 5859 | + 'securepoll-change-disallowed' => 'Du har redan deltagit i den här omröstningen. |
4834 | 5860 | Du kan tyvärr inte rösta igen.', |
4835 | 5861 | 'securepoll-change-allowed' => '<strong>Observera att du redan har röstat i den här omröstningen.</strong> |
4836 | 5862 | Du kan ändra din röst genom att skicka in formuläret nedan. |
— | — | @@ -4860,10 +5886,11 @@ |
4861 | 5887 | 'securepoll-no-decryption-key' => 'Ingen dekrypteringsnyckel är konfigurerad. |
4862 | 5888 | Kan inte dekryptera.', |
4863 | 5889 | 'securepoll-jump' => 'Gå till röstnings-servern.', |
4864 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
4865 | | -Din röst var ogiltig: $1 |
4866 | | -</div>', |
| 5890 | + 'securepoll-bad-ballot-submission' => 'Din röst var ogiltig: $1', |
4867 | 5891 | 'securepoll-unanswered-questions' => 'Du måste svara på alla frågor.', |
| 5892 | + 'securepoll-invalid-rank' => 'Ogiltig rangordning. Du måste rangordna kandidater mellan 1 och 999.', |
| 5893 | + 'securepoll-unranked-options' => 'Något eller några valmöjligheter rangordnades inte. |
| 5894 | +Du måste rangordna alla valmöjligheter mellan 1 och 999.', |
4868 | 5895 | 'securepoll-remote-auth-error' => 'Fel uppstod vid hämtning av din kontoinformation från servern.', |
4869 | 5896 | 'securepoll-remote-parse-error' => 'Fel uppstod vid tolkning av auktorisationssvar från servern.', |
4870 | 5897 | 'securepoll-api-invalid-params' => 'Felaktig parameter.', |
— | — | @@ -4888,13 +5915,14 @@ |
4889 | 5916 | 'securepoll-strike-reason' => 'Anledning:', |
4890 | 5917 | 'securepoll-strike-cancel' => 'Avbryt', |
4891 | 5918 | 'securepoll-strike-error' => 'Fel vid borttagning eller upphävning av borttagning: $1', |
| 5919 | + 'securepoll-strike-token-mismatch' => 'Tappade sessionsdata', |
4892 | 5920 | 'securepoll-details-link' => 'Detaljer', |
4893 | 5921 | 'securepoll-details-title' => 'Röstningsdetaljer: #$1', |
4894 | 5922 | 'securepoll-invalid-vote' => '"$1" är inte en giltig röst.', |
4895 | 5923 | 'securepoll-header-voter-type' => 'Röstningstyp', |
4896 | 5924 | 'securepoll-voter-properties' => 'Väljaregenskaper', |
4897 | 5925 | 'securepoll-strike-log' => 'Borttagningslogg', |
4898 | | - 'securepoll-header-action' => 'Handling', |
| 5926 | + 'securepoll-header-action' => 'Åtgärd', |
4899 | 5927 | 'securepoll-header-reason' => 'Anledning', |
4900 | 5928 | 'securepoll-header-admin' => 'Administratör', |
4901 | 5929 | 'securepoll-cookie-dup-list' => 'Cookie dubblettanvändare', |
— | — | @@ -4903,6 +5931,8 @@ |
4904 | 5932 | 'securepoll-dump-not-finished' => 'Krypterade valregister finns endast tillgängliga efter avslutandet den $1 klockan $2', |
4905 | 5933 | 'securepoll-dump-no-urandom' => 'Kan inte öppna /dev/urandom. |
4906 | 5934 | För att säkra en hemlig omröstning är de krypterade valregisterna endast tillgängliga offentligt när de kan blandas av en säker ström av tillfälliga tal.', |
| 5935 | + 'securepoll-urandom-not-supported' => 'Den här servern har inte stöd för att generera slumpmässiga tal för kryptering. |
| 5936 | +För att säkerställa väljarnas integritet så kan krypterade valresultat enbart göras allmänt tillgängliga om de kan blandas med en säker slumptalsgenerator.', |
4907 | 5937 | 'securepoll-translate-title' => 'Översätt: $1', |
4908 | 5938 | 'securepoll-invalid-language' => 'Felaktig språkkod "$1"', |
4909 | 5939 | 'securepoll-submit-translate' => 'Uppdatera', |
— | — | @@ -4920,22 +5950,76 @@ |
4921 | 5951 | 'securepoll-tally-not-finished' => 'Beklagar, du kan inte räkna upp valresultatet innan omröstningen är slutförd.', |
4922 | 5952 | 'securepoll-can-decrypt' => 'Valregistret har krypterats, men dekrypteringsnyckeln finns tillgänglig. |
4923 | 5953 | Du kan välja att antingen räkna upp resultaten som finns tillgängliga i databasen eller räkna upp de krypterade resultaten från en uppladdad fil.', |
| 5954 | + 'securepoll-tally-no-key' => 'Du kan inte kontrollräkna det här valet eftersom rösterna är krypterade, och det finns ingen tillgänglig nyckel för att dekryptera dem.', |
| 5955 | + 'securepoll-tally-local-legend' => 'Kontrollräkna lagrat resultat.', |
| 5956 | + 'securepoll-tally-local-submit' => 'Skapa rösträkning', |
| 5957 | + 'securepoll-tally-upload-legend' => 'Ladda upp krypterad dump.', |
| 5958 | + 'securepoll-tally-upload-submit' => 'Skapa rösträkning', |
| 5959 | + 'securepoll-tally-error' => 'Fel vid läsning av röstlängd, kan inte skapa rösträkning.', |
| 5960 | + 'securepoll-no-upload' => 'Ingen fil laddades upp, kan inte räkna fram ett resultat.', |
| 5961 | + 'securepoll-dump-corrupt' => 'Dumpningsfilen är korrupt och kan inte bearbetas.', |
| 5962 | + 'securepoll-tally-upload-error' => 'Fel vid rösträkning av dumpfil: $1', |
4924 | 5963 | ); |
4925 | 5964 | |
4926 | 5965 | /** Telugu (తెలుగు) |
| 5966 | + * @author Kiranmayee |
4927 | 5967 | * @author Veeven |
4928 | 5968 | */ |
4929 | 5969 | $messages['te'] = array( |
| 5970 | + 'securepoll' => 'సంరక్షితఎన్నిక', |
| 5971 | + 'securepoll-desc' => 'ఎన్నికలకు, సర్వేలకు పొడగింపు', |
| 5972 | + 'securepoll-need-admin' => 'ఈ పని పూర్తి చేయటకు మీరు అధికారి హోదా కలిగి వుండాలి.', |
| 5973 | + 'securepoll-invalid-election' => '"$1" అన్నది సరైన ఎన్నిక గుర్తింపు కాదు.', |
| 5974 | + 'securepoll-welcome' => '<strong>స్వాగతం $1!</strong>', |
| 5975 | + 'securepoll-not-started' => 'ఈ ఎన్నిక ఇంకా మొదలు అవ్వలేదు. |
| 5976 | +$2 న, $3 లకు మోదలు అవుతుంది', |
| 5977 | + 'securepoll-finished' => 'ఈ ఎన్నిక పూర్తి అయినది. |
| 5978 | +తమరు ఇంక వోటు వేయలేరు.', |
| 5979 | + 'securepoll-not-qualified' => 'తమరికి ఈ ఎన్నికలలో వుతూ వినియోగించుకునే అర్హత లేదు: $1', |
| 5980 | + 'securepoll-change-disallowed' => 'తమరు ఇదివరకే ఈ ఎన్నికలలో వోటు వేసారు. |
| 5981 | +క్షమించండి, తమరు మళ్లీ వోటు వేయలేరు.', |
| 5982 | + 'securepoll-change-allowed' => '<strong>తమరు ఇదివరకే ఈ ఎన్నికలలో వోటు వేసారు.</strong> |
| 5983 | +తమ వోటుని మార్చుకోవడానికి క్రింది ఫాంను పూర్తి చేసి పంపండి. |
| 5984 | +గుర్తుంచుకోండి, కొత్త ఫాంను పంపిస్తే,తమ పాత వోటుకి విలువ వుండదు.', |
| 5985 | + 'securepoll-submit' => 'వోటు వేయి', |
| 5986 | + 'securepoll-gpg-receipt' => 'వోటు వేసినందుకు ధన్యవాదాలు. మీకు అవసరము అనుకుంటే, క్రింది రసీదుని మీ వోటుకి గుర్తుగా భద్రపరచుకోండి. |
| 5987 | +<pre>$1</pre>', |
| 5988 | + 'securepoll-thanks' => 'ధన్యవాదాలు! మీ వోటుని భద్రపరచడమైనది.', |
| 5989 | + 'securepoll-return' => 'తిరిగి $1కి', |
| 5990 | + 'securepoll-jump' => 'వోటింగ్ సర్వరుకు వెళ్ళుము', |
| 5991 | + 'securepoll-unanswered-questions' => 'మీరు అన్ని ప్రశ్నలకి సమాధానము ఇవ్వవలెను.', |
| 5992 | + 'securepoll-not-logged-in' => 'ఈ ఎన్నికలో తమ వోటు హక్కును వినియోగించుకునేందుకు తమరు లోనికి ప్రవేశించి ఉండాలి', |
| 5993 | + 'securepoll-too-few-edits' => 'క్షమించండి, తమరు వోటు వేయలేరు. ఈ ఎన్నికలో వోటు వేసేందుకు తమరు కనీసము $1 {{PLURAL:$1|మార్పు|మార్పులు}} చేసివుండాలి, కాని తమరు $2 చేసారు.', |
4930 | 5994 | 'securepoll-header-timestamp' => 'సమయం', |
4931 | 5995 | 'securepoll-header-voter-name' => 'పేరు', |
| 5996 | + 'securepoll-header-ua' => 'వాడుకరి తరుపు ఏజంటు', |
| 5997 | + 'securepoll-header-strike' => 'కొట్టివేయి', |
4932 | 5998 | 'securepoll-header-details' => 'వివరాలు', |
| 5999 | + 'securepoll-strike-button' => 'కొట్టివేయి', |
| 6000 | + 'securepoll-unstrike-button' => 'కొట్టివేత తుడుపు', |
4933 | 6001 | 'securepoll-strike-reason' => 'కారణం:', |
| 6002 | + 'securepoll-strike-cancel' => 'రద్దు', |
4934 | 6003 | 'securepoll-details-link' => 'వివరాలు', |
| 6004 | + 'securepoll-details-title' => 'వోటు వివరాలు: #$1', |
4935 | 6005 | 'securepoll-header-action' => 'చర్య', |
4936 | 6006 | 'securepoll-header-reason' => 'కారణం', |
| 6007 | + 'securepoll-header-admin' => 'నిర్వహణాధికారి', |
| 6008 | + 'securepoll-translate-title' => 'అనువదించు: $1', |
| 6009 | + 'securepoll-submit-translate' => 'అప్డేట్', |
| 6010 | + 'securepoll-language-label' => 'భాషను ఎన్నుకో:', |
| 6011 | + 'securepoll-submit-select-lang' => 'అనువదించు', |
4937 | 6012 | 'securepoll-header-title' => 'పేరు', |
4938 | 6013 | 'securepoll-header-start-date' => 'ఆరంభ తేదీ', |
4939 | 6014 | 'securepoll-header-end-date' => 'ముగింపు తేదీ', |
| 6015 | + 'securepoll-subpage-vote' => 'వోటు', |
| 6016 | + 'securepoll-subpage-translate' => 'అనువదించు', |
| 6017 | + 'securepoll-subpage-list' => 'జాబితా', |
| 6018 | + 'securepoll-subpage-tally' => 'సరిచూడు', |
| 6019 | + 'securepoll-tally-title' => 'సరిచూడు: $1', |
| 6020 | + 'securepoll-tally-not-finished' => 'క్షమించండి, వోటింగు పూర్తి అయ్యే దాకా ఎన్నికను సరిచూడలేరు.', |
| 6021 | + 'securepoll-tally-local-legend' => 'భద్రపరిచిన ఫలితాలను సరిచూడు', |
| 6022 | + 'securepoll-tally-error' => 'వోటు రికార్డును అర్ధం చేసుకోవదములో తప్పు దొర్లినది, లెక్కలను సరిచూడలేము.', |
| 6023 | + 'securepoll-no-upload' => 'ఫైల్ ఏమి అప్లోడ్ అవ్వబడలేదు, ఫలితాలను సరి చూడలేము.', |
4940 | 6024 | ); |
4941 | 6025 | |
4942 | 6026 | /** Thai (ไทย) |
— | — | @@ -5010,9 +6094,7 @@ |
5011 | 6095 | 'securepoll-no-decryption-key' => 'Walang nakaayos na susing pangtanggal ng kodigo. |
5012 | 6096 | Hindi matanggal ang kodigo.', |
5013 | 6097 | 'securepoll-jump' => 'Pumunta sa tagapaghain ng pagboto', |
5014 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
5015 | | -Hindi tinanggap ang boto mo: $1 |
5016 | | -</div>', |
| 6098 | + 'securepoll-bad-ballot-submission' => 'Hindi tinanggap ang boto mo: $1', |
5017 | 6099 | 'securepoll-unanswered-questions' => 'Dapat mong sagutin ang lahat ng mga katanungan.', |
5018 | 6100 | 'securepoll-remote-auth-error' => 'Kamalian sa pagpulot ng kabatiran ng akawnt mo mula sa tagapaghain.', |
5019 | 6101 | 'securepoll-remote-parse-error' => 'Kamalian sa pagpapaliwanag ng tugon ng pagpapahintulot mula sa tagapaghain.', |
— | — | @@ -5081,6 +6163,7 @@ |
5082 | 6164 | |
5083 | 6165 | /** Turkish (Türkçe) |
5084 | 6166 | * @author Joseph |
| 6167 | + * @author Noumenon |
5085 | 6168 | */ |
5086 | 6169 | $messages['tr'] = array( |
5087 | 6170 | 'securepoll' => 'GüvenliAnket', |
— | — | @@ -5106,7 +6189,7 @@ |
5107 | 6190 | |
5108 | 6191 | <pre>$1</pre>', |
5109 | 6192 | 'securepoll-thanks' => 'Teşekkürler, oyunuz kaydedildi.', |
5110 | | - 'securepoll-return' => "$1'e geri dön", |
| 6193 | + 'securepoll-return' => '$1 sayfasına geri dön', |
5111 | 6194 | 'securepoll-encrypt-error' => 'Oy kaydınızın şifrelenmesi başarısız oldu. |
5112 | 6195 | Oyunuz kaydedilmedi! |
5113 | 6196 | |
— | — | @@ -5127,6 +6210,9 @@ |
5128 | 6211 | 'securepoll-jump' => 'Oylama sunucusuna git', |
5129 | 6212 | 'securepoll-bad-ballot-submission' => 'Oyunuz geçersiz: $1', |
5130 | 6213 | 'securepoll-unanswered-questions' => 'Tüm sorulara cevap vermelisiniz.', |
| 6214 | + 'securepoll-invalid-rank' => 'Geçersiz derece. Adaylara 1 ile 999 arasında bir derece vermelisiniz.', |
| 6215 | + 'securepoll-unranked-options' => 'Bazı seçenekler derecelendirilmemiş. |
| 6216 | +Tüm seçeneklere 1 ile 999 arasında bir derece vermelisiniz.', |
5131 | 6217 | 'securepoll-remote-auth-error' => 'Sunucudan hesap bilgileriniz alınırken hata.', |
5132 | 6218 | 'securepoll-remote-parse-error' => 'Sunucunun yetkilendirme cevabı değerlendirilirken hata.', |
5133 | 6219 | 'securepoll-api-invalid-params' => 'Geçersiz değişkenler.', |
— | — | @@ -5151,6 +6237,7 @@ |
5152 | 6238 | 'securepoll-strike-reason' => 'Sebep:', |
5153 | 6239 | 'securepoll-strike-cancel' => 'İptal', |
5154 | 6240 | 'securepoll-strike-error' => 'Üsütünü çiz/çizme yerine getirilirken hata: $1', |
| 6241 | + 'securepoll-strike-token-mismatch' => 'Oturum verileri kayıp', |
5155 | 6242 | 'securepoll-details-link' => 'Ayrıntılar', |
5156 | 6243 | 'securepoll-details-title' => 'Oy ayrıntıları: #$1', |
5157 | 6244 | 'securepoll-invalid-vote' => '"$1" geçerli bir oy IDsi değil', |
— | — | @@ -5166,6 +6253,8 @@ |
5167 | 6254 | 'securepoll-dump-not-finished' => "Şifreli seçim kayıtları sadece bitiş tarihi $1 saat $2'den sonra mevcut olur", |
5168 | 6255 | 'securepoll-dump-no-urandom' => '/dev/urandom açılamıyor. |
5169 | 6256 | Seçmen gizliliğini idame etmek için, şifreli seçim kayıtları sadece güvenli bir rasgele sayı akıntısıyla karıştırılabilirse umumen mevcut olur.', |
| 6257 | + 'securepoll-urandom-not-supported' => 'Bu sunucu kriptografik rastgele sayı üretimini desteklememektedir. |
| 6258 | +Oy veren gizliliğini sağlamak için, şifrelenmiş oylama kayıtları sadece güvenli bir rastgele sayı akışıyla karıştırılabilecekleri durumda alenen erişilebilirdirler.', |
5170 | 6259 | 'securepoll-translate-title' => 'Çevir: $1', |
5171 | 6260 | 'securepoll-invalid-language' => 'Geçersiz dil kodu "$1"', |
5172 | 6261 | 'securepoll-submit-translate' => 'Güncelle', |
— | — | @@ -5190,8 +6279,133 @@ |
5191 | 6280 | 'securepoll-tally-upload-submit' => 'Sayım oluştur', |
5192 | 6281 | 'securepoll-tally-error' => 'Oy kaydı yorumlanırken hata, bir sayım üretilemiyor.', |
5193 | 6282 | 'securepoll-no-upload' => 'Hiçbir dosya yüklenmedi, sonuçlar sayılamıyor.', |
| 6283 | + 'securepoll-dump-corrupt' => 'Yığın dosyası bozuk ve işlenebilir değil.', |
| 6284 | + 'securepoll-tally-upload-error' => 'Yığın dosyası sayımında hata: $1', |
5194 | 6285 | ); |
5195 | 6286 | |
| 6287 | +/** Ukrainian (Українська) |
| 6288 | + * @author AS |
| 6289 | + * @author Ahonc |
| 6290 | + * @author Ilyaroz |
| 6291 | + */ |
| 6292 | +$messages['uk'] = array( |
| 6293 | + 'securepoll' => 'Безпечне голосування', |
| 6294 | + 'securepoll-desc' => 'Розширення для проведення виборів і опитувань', |
| 6295 | + 'securepoll-invalid-page' => 'Помилкова підсторінка "<nowiki>$1</nowiki>"', |
| 6296 | + 'securepoll-need-admin' => 'Вам потрібно бути адміністртором, щоб виконати цю дію.', |
| 6297 | + 'securepoll-too-few-params' => 'Не вистачає параметрів підсторінки (помилкове посилання).', |
| 6298 | + 'securepoll-invalid-election' => '«$1» не є допустимим виборчим ідентифікатором.', |
| 6299 | + 'securepoll-welcome' => '<strong>Ласкаво просимо, $1!</strong>', |
| 6300 | + 'securepoll-not-started' => 'Ці вибори ще не розпочалися. |
| 6301 | +Початок запланований на $2 $3.', |
| 6302 | + 'securepoll-finished' => 'Ці вибори зкінчились, ви вже не можете проголосувати.', |
| 6303 | + 'securepoll-not-qualified' => 'Ви не уповноважені голосувати на цих виборах: $1', |
| 6304 | + 'securepoll-change-disallowed' => 'Ви вже голосували на цих виборах раніше. |
| 6305 | +Даруйте, ви не можете проголосувати ще раз.', |
| 6306 | + 'securepoll-change-allowed' => '<strong>Примітка: ви вже проголосували на цих виборах.</strong> |
| 6307 | +Ви можете змінити свій голос, відправивши приведену нижче форму. |
| 6308 | +Якщо ви зробите це, то ваш попередній голос не буде врахований.', |
| 6309 | + 'securepoll-submit' => 'Відправити голос', |
| 6310 | + 'securepoll-gpg-receipt' => 'Дякуємо за участь в голосуванні. |
| 6311 | + |
| 6312 | +При бажання ви можете зберегти наступні рядки як підтвердження вашого голосу: |
| 6313 | + |
| 6314 | +<pre>$1</pre>', |
| 6315 | + 'securepoll-thanks' => 'Спасибі, ваш голос записаний.', |
| 6316 | + 'securepoll-return' => 'Повернутись до $1', |
| 6317 | + 'securepoll-encrypt-error' => 'Не вдалося зашифрувати запис про ваш голос. |
| 6318 | +Ваш голос не був записаний! |
| 6319 | + |
| 6320 | +$1', |
| 6321 | + 'securepoll-no-gpg-home' => 'Не в змозі створити домашню теку GPG.', |
| 6322 | + 'securepoll-secret-gpg-error' => 'Помилка виконання GPG. |
| 6323 | +Задайте $wgSecurePollShowErrorDetail=true; в файлі LocalSettings.php щоб отримати докладніше повідомлення.', |
| 6324 | + 'securepoll-full-gpg-error' => 'Помилка виконання GPG: |
| 6325 | + |
| 6326 | +Команда: $1 |
| 6327 | + |
| 6328 | +Помилка: |
| 6329 | +<pre>$2</pre>', |
| 6330 | + 'securepoll-gpg-config-error' => 'GPG-ключі налаштовані неправильно.', |
| 6331 | + 'securepoll-gpg-parse-error' => 'Помилка при інтерпретації результату GPG.', |
| 6332 | + 'securepoll-no-decryption-key' => 'Не налаштований ключ розшифрування. |
| 6333 | +Не в змозі розшифрувати.', |
| 6334 | + 'securepoll-jump' => 'Перейти на сервер голосувань', |
| 6335 | + 'securepoll-bad-ballot-submission' => 'Ваш голос не дійсний: $1', |
| 6336 | + 'securepoll-unanswered-questions' => 'Ви повинні відповісти на всі запитання.', |
| 6337 | + 'securepoll-invalid-rank' => 'Неправильне місце. Ви повинні вказати для кандидата місце від 1 до 999.', |
| 6338 | + 'securepoll-unranked-options' => 'Для деяких записів не зазначені місця. |
| 6339 | +Вам слід вказати місця від 1 до 999 для кожного запису.', |
| 6340 | + 'securepoll-remote-auth-error' => 'Помилка отримання інформації з сервера про ваш обліковий запис.', |
| 6341 | + 'securepoll-remote-parse-error' => 'Помилка інтерпретації відповіді від авторизації з сервера.', |
| 6342 | + 'securepoll-api-invalid-params' => 'Помилкові параметри.', |
| 6343 | + 'securepoll-api-no-user' => 'Не знайдений користувач із заданим ідентифікатором.', |
| 6344 | + 'securepoll-api-token-mismatch' => 'Невідповідність коду безпеки, не в змозі ввійти до системи.', |
| 6345 | + 'securepoll-not-logged-in' => 'Ви маєте ввійти до системи, щоб взяти участь в голосуванні', |
| 6346 | + 'securepoll-too-few-edits' => 'Вибачте, ви не можете проголосувати. Вам треба мати не менше $1 {{PLURAL:$1|редагування|редагувань|редагувань}} для участі в цьому голосуванні, у вас є $2.', |
| 6347 | + 'securepoll-blocked' => 'Вибачте, ви не можете голосувати на виборах, оскільки вас заблоковано.', |
| 6348 | + 'securepoll-bot' => 'Вибачте, облікові записи зі статусом бота не допускаються до участі в голосуванні.', |
| 6349 | + 'securepoll-not-in-group' => 'Тільки члени групи "$1" можуть голосувати на цих виборах.', |
| 6350 | + 'securepoll-not-in-list' => 'Вибачте, ви не входите в список користувачів, допущених до голосування на цих виборах.', |
| 6351 | + 'securepoll-list-title' => 'Список голосів: $1', |
| 6352 | + 'securepoll-header-timestamp' => 'Час', |
| 6353 | + 'securepoll-header-voter-name' => "Ім'я", |
| 6354 | + 'securepoll-header-voter-domain' => 'Домен', |
| 6355 | + 'securepoll-header-ua' => 'Програма клієнта', |
| 6356 | + 'securepoll-header-cookie-dup' => 'Дубл.', |
| 6357 | + 'securepoll-header-strike' => 'Закреслення', |
| 6358 | + 'securepoll-header-details' => 'Деталі', |
| 6359 | + 'securepoll-strike-button' => 'Закреслити', |
| 6360 | + 'securepoll-unstrike-button' => 'Зняти закреслення', |
| 6361 | + 'securepoll-strike-reason' => 'Причина:', |
| 6362 | + 'securepoll-strike-cancel' => 'Скасувати', |
| 6363 | + 'securepoll-strike-error' => 'Помилка при викреслюванні/знятті викреслювання: $1', |
| 6364 | + 'securepoll-strike-token-mismatch' => 'Дані сеансу втрачені', |
| 6365 | + 'securepoll-details-link' => 'Докладніше', |
| 6366 | + 'securepoll-details-title' => 'Деталі голосування: #$1', |
| 6367 | + 'securepoll-invalid-vote' => '«$1» — неправильний ідентифікатор голосування', |
| 6368 | + 'securepoll-header-voter-type' => 'Тип виборця', |
| 6369 | + 'securepoll-voter-properties' => 'Властивості виборця', |
| 6370 | + 'securepoll-strike-log' => 'Журнал викреслювань', |
| 6371 | + 'securepoll-header-action' => 'Дія', |
| 6372 | + 'securepoll-header-reason' => 'Причина', |
| 6373 | + 'securepoll-header-admin' => 'Адміністратор', |
| 6374 | + 'securepoll-cookie-dup-list' => 'Дублікати користувачів за куками', |
| 6375 | + 'securepoll-dump-title' => 'Дамп: $1', |
| 6376 | + 'securepoll-dump-no-crypt' => 'Незашифровані записи подачі голосу доступні на цих виборах, оскільки вибори не налаштовані на використання шифрування.', |
| 6377 | + 'securepoll-dump-not-finished' => 'Зашифровані записи голосів доступні тільки після закінчення голосування $1 о $2', |
| 6378 | + 'securepoll-dump-no-urandom' => 'Не вдається відкрити /dev/urandom. |
| 6379 | +Для забезпечення конфіденційності виборців, зашифровані записи подачі голосів можна робити загальнодоступними, тільки коли порядок їх слідування можна змінити з використанням безпечного джерела випадкових чисел.', |
| 6380 | + 'securepoll-urandom-not-supported' => 'Цей сервер не підтримує криптографічні генерування випадкових чисел. |
| 6381 | +Щоб зберегти конфіденційність голосуючих, закодовані записи голосування стануть загальнодоступними тільки після того, як вони зможуть бути перемішані за допомогою безпечного потоку випадкових чисел.', |
| 6382 | + 'securepoll-translate-title' => 'Переклад: $1', |
| 6383 | + 'securepoll-invalid-language' => 'Неправильний код мови «$1»', |
| 6384 | + 'securepoll-submit-translate' => 'Оновити', |
| 6385 | + 'securepoll-language-label' => 'Вибір мови:', |
| 6386 | + 'securepoll-submit-select-lang' => 'Перекласти', |
| 6387 | + 'securepoll-header-title' => "Ім'я", |
| 6388 | + 'securepoll-header-start-date' => 'Дата початку', |
| 6389 | + 'securepoll-header-end-date' => 'Дата закінчення', |
| 6390 | + 'securepoll-subpage-vote' => 'Голосування', |
| 6391 | + 'securepoll-subpage-translate' => 'Переклад', |
| 6392 | + 'securepoll-subpage-list' => 'Список', |
| 6393 | + 'securepoll-subpage-dump' => 'Дамп', |
| 6394 | + 'securepoll-subpage-tally' => 'Підрахунок', |
| 6395 | + 'securepoll-tally-title' => 'Підрахунок: $1', |
| 6396 | + 'securepoll-tally-not-finished' => 'Вибачте, ви можете проводити підрахунок підсумків тільки після завершення голосування.', |
| 6397 | + 'securepoll-can-decrypt' => 'Запис голосування був зашифрований, але є ключ розшифровки. |
| 6398 | +Ви можете обрати або підрахунок поточних результатів в базі даних, або підрахунок зашифрованих результатів з завантаженого файлу.', |
| 6399 | + 'securepoll-tally-no-key' => 'Ви можете не підраховувати голоси на цих виборах, так як вони були зашифровані, а ключ розшифровки відсутній.', |
| 6400 | + 'securepoll-tally-local-legend' => 'Підрахунок збережених результатів', |
| 6401 | + 'securepoll-tally-local-submit' => 'Зробити підрахунок', |
| 6402 | + 'securepoll-tally-upload-legend' => 'Завантаження зашифрованого скиду (дампу)', |
| 6403 | + 'securepoll-tally-upload-submit' => 'Зробити підрахунок', |
| 6404 | + 'securepoll-tally-error' => 'Помилка інтерпретації запису голосу, неможливо провести підрахунок.', |
| 6405 | + 'securepoll-no-upload' => 'Файл не був завантажений, неможливо підрахувати результати.', |
| 6406 | + 'securepoll-dump-corrupt' => 'Файл скиду (дампу) пошкоджений і не може бути обробленим.', |
| 6407 | + 'securepoll-tally-upload-error' => 'Помилка під час підрахунків у файлі скиду (дампу): $1', |
| 6408 | +); |
| 6409 | + |
5196 | 6410 | /** Urdu (اردو) |
5197 | 6411 | * @author محبوب عالم |
5198 | 6412 | */ |
— | — | @@ -5269,9 +6483,7 @@ |
5270 | 6484 | 'securepoll-no-decryption-key' => 'No xe stà configurà nissuna ciave de decritassion. |
5271 | 6485 | No se pole decritar.', |
5272 | 6486 | 'securepoll-jump' => 'Và al server de ła votasion', |
5273 | | - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box"> |
5274 | | -El to voto no\'l xe mia vàłido: $1 |
5275 | | -</div>', |
| 6487 | + 'securepoll-bad-ballot-submission' => "El to voto no'l xe mia vàłido: $1", |
5276 | 6488 | 'securepoll-unanswered-questions' => 'Ti gà da rispóndar a tute le domande.', |
5277 | 6489 | 'securepoll-remote-auth-error' => 'Eròr durante el recupero de le informassion su la to utensa dal server.', |
5278 | 6490 | 'securepoll-remote-parse-error' => 'Se gà verificà un eròr interpretando la risposta de autorixassion dal server.', |
— | — | @@ -5391,6 +6603,9 @@ |
5392 | 6604 | 'securepoll-jump' => 'Đi đến máy chủ bỏ phiếu', |
5393 | 6605 | 'securepoll-bad-ballot-submission' => 'Phiếu bầu của bạn không hợp lệ: $1', |
5394 | 6606 | 'securepoll-unanswered-questions' => 'Bạn phải trả lời tất cả các câu hỏi.', |
| 6607 | + 'securepoll-invalid-rank' => 'Xếp hạng không hợp lệ. Bạn phải xếp hạng cho ứng viên trong khoảng từ 1 đến 999.', |
| 6608 | + 'securepoll-unranked-options' => 'Một số ứng viên chưa được xếp hạng. |
| 6609 | +Bạn phải xếp hạng từ 1 đến 999 cho tất cả các ứng viên.', |
5395 | 6610 | 'securepoll-remote-auth-error' => 'Lỗi khi truy xuất thông tin tài khoản của bạn từ máy chủ.', |
5396 | 6611 | 'securepoll-remote-parse-error' => 'Lỗi khi thông dịch phản hồi ủy quyền từ máy chủ.', |
5397 | 6612 | 'securepoll-api-invalid-params' => 'Thông số không hợp lệ.', |
— | — | @@ -5415,6 +6630,7 @@ |
5416 | 6631 | 'securepoll-strike-reason' => 'Lý do:', |
5417 | 6632 | 'securepoll-strike-cancel' => 'Hủy bỏ', |
5418 | 6633 | 'securepoll-strike-error' => 'Lỗi khi gạch bỏ hay phục hồi: $1', |
| 6634 | + 'securepoll-strike-token-mismatch' => 'Mất dữ liệu phiên', |
5419 | 6635 | 'securepoll-details-link' => 'Chi tiết', |
5420 | 6636 | 'securepoll-details-title' => 'Chi tiết lá phiếu: #$1', |
5421 | 6637 | 'securepoll-invalid-vote' => '“$1” không phải là mã lá phiếu hợp lệ', |
— | — | @@ -5430,6 +6646,8 @@ |
5431 | 6647 | 'securepoll-dump-not-finished' => 'Hồ sơ bầu cử đã mã hóa chỉ có sau khi kết thúc vào ngày $1 lúc $2', |
5432 | 6648 | 'securepoll-dump-no-urandom' => 'Không thể mở /dev/urandom. |
5433 | 6649 | Để bảo đảm quyền riêng tư của cử tri, các bản ghi bầu cử đã mã hóa cần được xáo trộn bằng dòng số ngẫu nhiên mã hóa trước khi công khai.', |
| 6650 | + 'securepoll-urandom-not-supported' => 'Máy chủ này không hỗ trợ tạo số ngẫu nhiên mã hóa. |
| 6651 | +Để duy trì bí mật danh tính cho người bỏ phiếu, các bản ghi bầu cử mã hóa chỉ hiển thị cho mọi người một khi chúng được xáo bằng một chuỗi số ngẫu nhiên an toàn.', |
5434 | 6652 | 'securepoll-translate-title' => 'Biên dịch: $1', |
5435 | 6653 | 'securepoll-invalid-language' => 'Mã ngôn ngữ “$1” không hợp lệ', |
5436 | 6654 | 'securepoll-submit-translate' => 'Cập nhật', |
— | — | @@ -5454,8 +6672,43 @@ |
5455 | 6673 | 'securepoll-tally-upload-submit' => 'Tạo cuộc kiểm phiếu', |
5456 | 6674 | 'securepoll-tally-error' => 'Lỗi khi thông dịch bản ghi lá phiếu, không thể tạo cuộc kiểm phiếu.', |
5457 | 6675 | 'securepoll-no-upload' => 'Không có tập tin nào được tải lên, không thể kiểm phiếu.', |
| 6676 | + 'securepoll-dump-corrupt' => 'Tập tin kho bị hư và không thể được xử lý.', |
| 6677 | + 'securepoll-tally-upload-error' => 'Có lỗi khi kiểm tập tin kho: $1', |
| 6678 | + 'securepoll-pairwise-victories' => 'Ma trận chiến thắng theo cặp', |
| 6679 | + 'securepoll-strength-matrix' => 'Ma trận độ mạnh đường đi', |
| 6680 | + 'securepoll-ranks' => 'Xếp hạng sau cùng', |
5458 | 6681 | ); |
5459 | 6682 | |
| 6683 | +/** Yiddish (ייִדיש) |
| 6684 | + * @author פוילישער |
| 6685 | + */ |
| 6686 | +$messages['yi'] = array( |
| 6687 | + 'securepoll-invalid-page' => 'אומגילטיקער אונטערבלאט "<nowiki>$1</nowiki>"', |
| 6688 | + 'securepoll-need-admin' => 'איר דארפט זיין א סיסאפ אדורכצופירן די פעולה.', |
| 6689 | + 'securepoll-too-few-params' => 'נישט גענוג אונטערבלאט פאראמעטערס (אומגילטיקער לינק).', |
| 6690 | + 'securepoll-invalid-election' => '"$1" איז נישט קיין גילטיקער אפשטימונג ID.', |
| 6691 | + 'securepoll-welcome' => '<strong>ברוך הבא, $1!</strong>', |
| 6692 | + 'securepoll-not-started' => 'די אפשטימונג האט נאך נישט אנגעהויבן. |
| 6693 | +זי איז באשטימט אנצוהייבן אום $2 אזייגער $3.', |
| 6694 | + 'securepoll-finished' => 'די אפשטימונג האט שוין געקאנטשעט, איר קענט מער נישט אפשטימען.', |
| 6695 | + 'securepoll-gpg-receipt' => 'א דאנק פארן שטימען. |
| 6696 | + |
| 6697 | +ווען איר ווילט, קענט איר היטן דעם פאלגנדן קוויט אלס ראיה פון אייער שטים. |
| 6698 | + |
| 6699 | +<pre>$1</pre>', |
| 6700 | + 'securepoll-return' => 'צוריק צו $1', |
| 6701 | + 'securepoll-bad-ballot-submission' => 'אייער שטים איז געווען אומגילטיג.', |
| 6702 | + 'securepoll-unanswered-questions' => 'איר מוזט ענטפערן אלע שאלות.', |
| 6703 | + 'securepoll-api-invalid-params' => 'אומגילטיגע פאראמעטערס', |
| 6704 | + 'securepoll-header-timestamp' => 'צײַט', |
| 6705 | + 'securepoll-header-voter-name' => 'נאָמען', |
| 6706 | + 'securepoll-header-reason' => 'אורזאַך', |
| 6707 | + 'securepoll-submit-translate' => 'דערהײַנטיקן', |
| 6708 | + 'securepoll-submit-select-lang' => 'פארטייטשן', |
| 6709 | + 'securepoll-header-title' => 'נאָמען', |
| 6710 | + 'securepoll-subpage-list' => 'ליסטע', |
| 6711 | +); |
| 6712 | + |
5460 | 6713 | /** Yue (粵語) |
5461 | 6714 | * @author Shinjiman |
5462 | 6715 | */ |
— | — | @@ -5571,7 +6824,7 @@ |
5572 | 6825 | 'securepoll-no-upload' => '無檔案上載,整唔到記數結果。', |
5573 | 6826 | ); |
5574 | 6827 | |
5575 | | -/** Zhuang (Sawcuengh) |
| 6828 | +/** Zhuang (Vahcuengh) |
5576 | 6829 | * @author Biŋhai |
5577 | 6830 | */ |
5578 | 6831 | $messages['za'] = array( |
— | — | @@ -5591,6 +6844,7 @@ |
5592 | 6845 | * @author Bencmq |
5593 | 6846 | * @author Biŋhai |
5594 | 6847 | * @author FireJackey |
| 6848 | + * @author PhiLiP |
5595 | 6849 | * @author Skjackey tse |
5596 | 6850 | */ |
5597 | 6851 | $messages['zh-hans'] = array( |
— | — | @@ -5635,6 +6889,8 @@ |
5636 | 6890 | 'securepoll-jump' => '进入投票服务器', |
5637 | 6891 | 'securepoll-bad-ballot-submission' => '您的投票无效:$1', |
5638 | 6892 | 'securepoll-unanswered-questions' => '您必须回答所有问题。', |
| 6893 | + 'securepoll-invalid-rank' => '评级无效。给候选人的评级分数必须在1到999之间。', |
| 6894 | + 'securepoll-unranked-options' => '部分选项尚未评级。所有选项均应评级,且分数应在1到999之间。', |
5639 | 6895 | 'securepoll-remote-auth-error' => '从服务器提取您的用户信息时出错。', |
5640 | 6896 | 'securepoll-remote-parse-error' => '服务器验证出错。', |
5641 | 6897 | 'securepoll-api-invalid-params' => '参数无效。', |
— | — | @@ -5659,6 +6915,7 @@ |
5660 | 6916 | 'securepoll-strike-reason' => '理由:', |
5661 | 6917 | 'securepoll-strike-cancel' => '取消', |
5662 | 6918 | 'securepoll-strike-error' => '进行删除选票/恢复被删除选票时出错:$1', |
| 6919 | + 'securepoll-strike-token-mismatch' => '丢失会话数据', |
5663 | 6920 | 'securepoll-details-link' => '细节', |
5664 | 6921 | 'securepoll-details-title' => '投票细节:#$1', |
5665 | 6922 | 'securepoll-invalid-vote' => '“$1”不是有效的投票ID', |
— | — | @@ -5673,6 +6930,8 @@ |
5674 | 6931 | 'securepoll-dump-no-crypt' => '本次投票没有被加密的投票记录,因为它被配置为不须加密。', |
5675 | 6932 | 'securepoll-dump-not-finished' => '加密的投票记录只有在截止日期$1 $2后方可获得', |
5676 | 6933 | 'securepoll-dump-no-urandom' => '无法打开/dev/urandom。为了保证投票者的隐私,经过加密的投票记录只有在经随机数据串干涉后方可公开。', |
| 6934 | + 'securepoll-urandom-not-supported' => '本服务器并不支持密文随机数生成。 |
| 6935 | +为了保证投票者的隐私,经过加密的投票记录只有在经随机数据串干涉后方可公开。', |
5677 | 6936 | 'securepoll-translate-title' => '翻译:$1', |
5678 | 6937 | 'securepoll-invalid-language' => '无效的语言代码“$1”', |
5679 | 6938 | 'securepoll-submit-translate' => '更新', |
— | — | @@ -5696,11 +6955,15 @@ |
5697 | 6956 | 'securepoll-tally-upload-submit' => '创建点票数据', |
5698 | 6957 | 'securepoll-tally-error' => '处理投票记录时出错,无法创建点票数据。', |
5699 | 6958 | 'securepoll-no-upload' => '没有上传文件。', |
| 6959 | + 'securepoll-dump-corrupt' => '无法处理损坏的转储文件。', |
| 6960 | + 'securepoll-tally-upload-error' => '转储文件记录错误:$1', |
5700 | 6961 | ); |
5701 | 6962 | |
5702 | 6963 | /** Traditional Chinese (中文(繁體)) |
5703 | 6964 | * @author Alexsh |
5704 | 6965 | * @author Bencmq |
| 6966 | + * @author FireJackey |
| 6967 | + * @author PhiLiP |
5705 | 6968 | * @author Skjackey tse |
5706 | 6969 | * @author Wong128hk |
5707 | 6970 | */ |
— | — | @@ -5749,6 +7012,8 @@ |
5750 | 7013 | 'securepoll-jump' => '進入投票伺服器', |
5751 | 7014 | 'securepoll-bad-ballot-submission' => '您的投票無效︰$1', |
5752 | 7015 | 'securepoll-unanswered-questions' => '您必須回答所有問題。', |
| 7016 | + 'securepoll-invalid-rank' => '評級無效。給候選人的評級分數必須在1到999之間。', |
| 7017 | + 'securepoll-unranked-options' => '部分選項尚未評級。所有選項均應評級,且分數應在1到999之間。', |
5753 | 7018 | 'securepoll-remote-auth-error' => '在投票伺服器提取您的用户信息時出錯', |
5754 | 7019 | 'securepoll-remote-parse-error' => '伺服器驗證錯誤', |
5755 | 7020 | 'securepoll-api-invalid-params' => '參數無效', |
— | — | @@ -5773,6 +7038,7 @@ |
5774 | 7039 | 'securepoll-strike-reason' => '理由:', |
5775 | 7040 | 'securepoll-strike-cancel' => '取消', |
5776 | 7041 | 'securepoll-strike-error' => '進行刪除選票/恢復被刪除選票時出錯:$1', |
| 7042 | + 'securepoll-strike-token-mismatch' => '丟失會話資料', |
5777 | 7043 | 'securepoll-details-link' => '細節', |
5778 | 7044 | 'securepoll-details-title' => '投票詳情︰#$1', |
5779 | 7045 | 'securepoll-invalid-vote' => '「$1」不是有效的投票ID', |
— | — | @@ -5788,6 +7054,8 @@ |
5789 | 7055 | 'securepoll-dump-not-finished' => '被加密的投票記錄只有在截止日期$1 $2後方可取得', |
5790 | 7056 | 'securepoll-dump-no-urandom' => '無法打開/dev/urandom。 |
5791 | 7057 | 為了保證投票者的隱私,經過加密的投票記錄只有在經隨機數據串干擾後方可公開。', |
| 7058 | + 'securepoll-urandom-not-supported' => '本伺服器並不支持密文隨機數生成。 |
| 7059 | +為了保證投票者的隱私,經過加密的投票記錄只有在經隨機數據串干擾後方可公開。', |
5792 | 7060 | 'securepoll-translate-title' => '翻譯:$1', |
5793 | 7061 | 'securepoll-invalid-language' => '錯誤的語言代碼:「$1」', |
5794 | 7062 | 'securepoll-submit-translate' => '更新', |
— | — | @@ -5811,6 +7079,8 @@ |
5812 | 7080 | 'securepoll-tally-upload-submit' => '新增計票數據', |
5813 | 7081 | 'securepoll-tally-error' => '投票記錄發生錯誤,無法新增計票數據。', |
5814 | 7082 | 'securepoll-no-upload' => '沒有上傳文件。', |
| 7083 | + 'securepoll-dump-corrupt' => '無法處理損壞的轉儲檔案。', |
| 7084 | + 'securepoll-tally-upload-error' => '轉儲檔案記錄錯誤:$1', |
5815 | 7085 | ); |
5816 | 7086 | |
5817 | 7087 | /** Chinese (Hong Kong) (中文(香港)) |
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.php |
— | — | @@ -1,11 +1,8 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | | - * Wikimedia Foundation Board of Trustees Election |
5 | | - * |
6 | 4 | * @file |
7 | 5 | * @ingroup Extensions |
8 | 6 | * @author Tim Starling <tstarling@wikimedia.org> |
9 | | - * @author Kwan Ting Chan |
10 | 7 | * @link http://www.mediawiki.org/wiki/Extension:SecurePoll Documentation |
11 | 8 | */ |
12 | 9 | |
— | — | @@ -18,7 +15,7 @@ |
19 | 16 | $wgExtensionCredits['other'][] = array( |
20 | 17 | 'path' => __FILE__, |
21 | 18 | 'name' => 'SecurePoll', |
22 | | - 'author' => array( 'Tim Starling', 'Kwan Ting Chan', 'others' ), |
| 19 | + 'author' => array( 'Tim Starling', 'others' ), |
23 | 20 | 'url' => 'http://www.mediawiki.org/wiki/Extension:SecurePoll', |
24 | 21 | 'svn-date' => '$LastChangedDate$', |
25 | 22 | 'svn-revision' => '$LastChangedRevision$', |
— | — | @@ -50,21 +47,23 @@ |
51 | 48 | $wgExtensionMessagesFiles['SecurePoll'] = "$dir/SecurePoll.i18n.php"; |
52 | 49 | $wgExtensionAliasesFiles['SecurePoll'] = "$dir/SecurePoll.alias.php"; |
53 | 50 | |
54 | | -$wgAutoloadClasses['SecurePollPage'] = "$dir/SecurePoll_body.php"; |
55 | | -$wgSpecialPages['SecurePoll'] = 'SecurePollPage'; |
| 51 | +$wgSpecialPages['SecurePoll'] = 'SecurePoll_BasePage'; |
56 | 52 | |
57 | 53 | $wgAutoloadClasses = $wgAutoloadClasses + array( |
58 | 54 | 'SecurePoll_Auth' => "$dir/includes/Auth.php", |
59 | 55 | 'SecurePoll_LocalAuth' => "$dir/includes/Auth.php", |
60 | 56 | 'SecurePoll_RemoteMWAuth' => "$dir/includes/Auth.php", |
61 | 57 | 'SecurePoll_Ballot' => "$dir/includes/Ballot.php", |
| 58 | + 'SecurePoll_BasePage' => "$dir/includes/Base.php", |
62 | 59 | 'SecurePoll_ChooseBallot' => "$dir/includes/Ballot.php", |
63 | 60 | 'SecurePoll_PreferentialBallot' => "$dir/includes/Ballot.php", |
| 61 | + 'SecurePoll_Context' => "$dir/includes/Context.php", |
64 | 62 | 'SecurePoll_Crypt' => "$dir/includes/Crypt.php", |
65 | 63 | 'SecurePoll_GpgCrypt' => "$dir/includes/Crypt.php", |
66 | 64 | 'SecurePoll_DetailsPage' => "$dir/includes/DetailsPage.php", |
67 | 65 | 'SecurePoll_DumpPage' => "$dir/includes/DumpPage.php", |
68 | 66 | 'SecurePoll_Election' => "$dir/includes/Election.php", |
| 67 | + 'SecurePoll_ElectionTallier' => "$dir/includes/ElectionTallier.php", |
69 | 68 | 'SecurePoll_Entity' => "$dir/includes/Entity.php", |
70 | 69 | 'SecurePoll_EntryPage' => "$dir/includes/EntryPage.php", |
71 | 70 | 'SecurePoll_ListPage' => "$dir/includes/ListPage.php", |
— | — | @@ -73,8 +72,14 @@ |
74 | 73 | 'SecurePoll_Option' => "$dir/includes/Option.php", |
75 | 74 | 'SecurePoll_Page' => "$dir/includes/Page.php", |
76 | 75 | 'SecurePoll_Question' => "$dir/includes/Question.php", |
| 76 | + 'SecurePoll_Random' => "$dir/includes/Random.php", |
| 77 | + 'SecurePoll_Store' => "$dir/includes/Store.php", |
| 78 | + 'SecurePoll_DBStore' => "$dir/includes/Store.php", |
| 79 | + 'SecurePoll_MemoryStore' => "$dir/includes/Store.php", |
| 80 | + 'SecurePoll_XMLStore' => "$dir/includes/Store.php", |
77 | 81 | 'SecurePoll_Tallier' => "$dir/includes/Tallier.php", |
78 | 82 | 'SecurePoll_PluralityTallier' => "$dir/includes/Tallier.php", |
| 83 | + 'SecurePoll_SchulzeTallier' => "$dir/includes/Tallier.php", |
79 | 84 | 'SecurePoll_TallyPage' => "$dir/includes/TallyPage.php", |
80 | 85 | 'SecurePoll_TranslatePage' => "$dir/includes/TranslatePage.php", |
81 | 86 | 'SecurePoll_Voter' => "$dir/includes/Voter.php", |
— | — | @@ -82,8 +87,12 @@ |
83 | 88 | ); |
84 | 89 | |
85 | 90 | $wgAjaxExportList[] = 'wfSecurePollStrike'; |
| 91 | +$wgHooks['UserLogout'][] = 'wfSecurePollLogout'; |
86 | 92 | |
87 | 93 | function wfSecurePollStrike( $action, $id, $reason ) { |
88 | 94 | return SecurePoll_ListPage::ajaxStrike( $action, $id, $reason ); |
89 | 95 | } |
90 | | - |
| 96 | +function wfSecurePollLogout( $user ) { |
| 97 | + $_SESSION['securepoll_voter'] = null; |
| 98 | + return true; |
| 99 | +} |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Auth.php |
— | — | @@ -4,6 +4,8 @@ |
5 | 5 | * Class for handling guest logins and sessions. Creates SecurePoll_Voter objects. |
6 | 6 | */ |
7 | 7 | class SecurePoll_Auth { |
| 8 | + var $context; |
| 9 | + |
8 | 10 | /** |
9 | 11 | * List of available authorisation modules (subclasses) |
10 | 12 | */ |
— | — | @@ -16,14 +18,18 @@ |
17 | 19 | * Create an auth object of the given type |
18 | 20 | * @param $type string |
19 | 21 | */ |
20 | | - static function factory( $type ) { |
| 22 | + static function factory( $context, $type ) { |
21 | 23 | if ( !isset( self::$authTypes[$type] ) ) { |
22 | 24 | throw new MWException( "Invalid authentication type: $type" ); |
23 | 25 | } |
24 | 26 | $class = self::$authTypes[$type]; |
25 | | - return new $class; |
| 27 | + return new $class( $context ); |
26 | 28 | } |
27 | 29 | |
| 30 | + function __construct( $context ) { |
| 31 | + $this->context = $context; |
| 32 | + } |
| 33 | + |
28 | 34 | /** |
29 | 35 | * Create a voter transparently, without user interaction. |
30 | 36 | * Sessions authorised against local accounts are created this way. |
— | — | @@ -68,7 +74,7 @@ |
69 | 75 | } |
70 | 76 | |
71 | 77 | # Sanity check election ID |
72 | | - $voter = SecurePoll_Voter::newFromId( $voterId ); |
| 78 | + $voter = $this->context->getVoter( $voterId ); |
73 | 79 | if ( !$voter || $voter->getElectionId() != $election->getId() ) { |
74 | 80 | return false; |
75 | 81 | } else { |
— | — | @@ -87,7 +93,7 @@ |
88 | 94 | * @return SecurePoll_Voter |
89 | 95 | */ |
90 | 96 | function getVoter( $params ) { |
91 | | - $dbw = wfGetDB( DB_MASTER ); |
| 97 | + $dbw = $this->context->getDB(); |
92 | 98 | |
93 | 99 | # This needs to be protected by FOR UPDATE |
94 | 100 | # Otherwise a race condition could lead to duplicate users for a single remote user, |
— | — | @@ -107,10 +113,10 @@ |
108 | 114 | if ( $row ) { |
109 | 115 | # No need to hold the lock longer |
110 | 116 | $dbw->commit(); |
111 | | - $user = SecurePoll_Voter::newFromRow( $row ); |
| 117 | + $user = $this->context->newVoterFromRow( $row ); |
112 | 118 | } else { |
113 | 119 | # Lock needs to be held until the row is inserted |
114 | | - $user = SecurePoll_Voter::createVoter( $params ); |
| 120 | + $user = $this->context->createVoter( $params ); |
115 | 121 | $dbw->commit(); |
116 | 122 | } |
117 | 123 | return $user; |
— | — | @@ -178,7 +184,7 @@ |
179 | 185 | if ( $wgUser->isAnon() ) { |
180 | 186 | return Status::newFatal( 'securepoll-not-logged-in' ); |
181 | 187 | } |
182 | | - $params = self::getUserParams( $wgUser ); |
| 188 | + $params = $this->getUserParams( $wgUser ); |
183 | 189 | $params['electionId'] = $election->getId(); |
184 | 190 | $qualStatus = $election->getQualifiedStatus( $params ); |
185 | 191 | if ( !$qualStatus->isOK() ) { |
— | — | @@ -193,7 +199,7 @@ |
194 | 200 | * @param $user User |
195 | 201 | * @return array |
196 | 202 | */ |
197 | | - static function getUserParams( $user ) { |
| 203 | + function getUserParams( $user ) { |
198 | 204 | global $wgServer; |
199 | 205 | if ( substr( $wgServer, 0, 5 ) == 'https' ) { |
200 | 206 | global $site, $lang; |
— | — | @@ -201,7 +207,7 @@ |
202 | 208 | } else { |
203 | 209 | $server = preg_replace( '!.*/(.*)$!', '$1', $wgServer ); |
204 | 210 | } |
205 | | - return array( |
| 211 | + $params = array( |
206 | 212 | 'name' => $user->getName(), |
207 | 213 | 'type' => 'local', |
208 | 214 | 'domain' => $server, |
— | — | @@ -213,9 +219,11 @@ |
214 | 220 | 'bot' => $user->isBot(), |
215 | 221 | 'language' => $user->getOption( 'language' ), |
216 | 222 | 'groups' => $user->getGroups(), |
217 | | - 'lists' => self::getLists( $user ) |
| 223 | + 'lists' => $this->getLists( $user ) |
218 | 224 | ) |
219 | 225 | ); |
| 226 | + wfRunHooks( 'SecurePoll_GetUserParams', array( $this, $user, &$params ) ); |
| 227 | + return $params; |
220 | 228 | } |
221 | 229 | |
222 | 230 | /** |
— | — | @@ -223,8 +231,8 @@ |
224 | 232 | * @param $user User |
225 | 233 | * @return array |
226 | 234 | */ |
227 | | - static function getLists( $user ) { |
228 | | - $dbr = wfGetDB( DB_SLAVE ); |
| 235 | + function getLists( $user ) { |
| 236 | + $dbr = $this->context->getDB(); |
229 | 237 | $res = $dbr->select( |
230 | 238 | 'securepoll_lists', |
231 | 239 | array( 'li_name' ), |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Crypt.php |
— | — | @@ -29,9 +29,9 @@ |
30 | 30 | * Create an encryption object of the given type. Currently only "gpg" is |
31 | 31 | * implemented. |
32 | 32 | */ |
33 | | - static function factory( $type, $election ) { |
| 33 | + static function factory( $context, $type, $election ) { |
34 | 34 | if ( $type === 'gpg' ) { |
35 | | - return new SecurePoll_GpgCrypt( $election ); |
| 35 | + return new SecurePoll_GpgCrypt( $context, $election ); |
36 | 36 | } else { |
37 | 37 | return false; |
38 | 38 | } |
— | — | @@ -50,14 +50,15 @@ |
51 | 51 | * gpg-decrypt-key is for tallying. |
52 | 52 | */ |
53 | 53 | class SecurePoll_GpgCrypt { |
54 | | - var $election; |
| 54 | + var $context, $election; |
55 | 55 | var $recipient, $signer, $homeDir; |
56 | 56 | |
57 | 57 | /** |
58 | 58 | * Constructor. |
59 | 59 | * @param $election SecurePoll_Election |
60 | 60 | */ |
61 | | - function __construct( $election ) { |
| 61 | + function __construct( $context, $election ) { |
| 62 | + $this->context = $context; |
62 | 63 | $this->election = $election; |
63 | 64 | } |
64 | 65 | |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/DumpPage.php |
— | — | @@ -4,6 +4,8 @@ |
5 | 5 | * Special:SecurePoll subpage for exporting encrypted election records. |
6 | 6 | */ |
7 | 7 | class SecurePoll_DumpPage extends SecurePoll_Page { |
| 8 | + var $headersSent; |
| 9 | + |
8 | 10 | /** |
9 | 11 | * Execute the subpage. |
10 | 12 | * @param $params array Array of subpage parameters. |
— | — | @@ -17,7 +19,7 @@ |
18 | 20 | } |
19 | 21 | |
20 | 22 | $electionId = intval( $params[0] ); |
21 | | - $this->election = $this->parent->getElection( $electionId ); |
| 23 | + $this->election = $this->context->getElection( $electionId ); |
22 | 24 | if ( !$this->election ) { |
23 | 25 | $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId ); |
24 | 26 | return; |
— | — | @@ -40,89 +42,36 @@ |
41 | 43 | return; |
42 | 44 | } |
43 | 45 | |
44 | | - if ( !$this->openRandom() ) { |
45 | | - $wgOut->addWikiMsg( 'securepoll-dump-no-urandom' ); |
| 46 | + $this->headersSent = false; |
| 47 | + $status = $this->election->dumpVotesToCallback( array( $this, 'dumpVote' ) ); |
| 48 | + if ( !$status->isOK() && !$this->headersSent ) { |
| 49 | + $wgOut->addWikiText( $status->getWikiText() ); |
46 | 50 | return; |
47 | 51 | } |
48 | | - |
49 | | - $wgOut->disable(); |
50 | | - header( 'Content-Type: text/plain' ); |
51 | | - $filename = urlencode( "SecurePoll-$electionId-" . wfTimestampNow() ); |
52 | | - header( "Content-Disposition: attachment; filename=$filename" ); |
53 | | - $db = wfGetDB( DB_SLAVE ); |
54 | | - $res = $db->select( |
55 | | - 'securepoll_votes', |
56 | | - array( 'vote_id', 'vote_record' ), |
57 | | - array( |
58 | | - 'vote_election' => $electionId, |
59 | | - 'vote_current' => 1, |
60 | | - 'vote_struck' => 0 |
61 | | - ), |
62 | | - __METHOD__ |
63 | | - ); |
64 | | - |
65 | | - $order = $this->shuffle( range( 0, $res->numRows() - 1 ) ); |
66 | | - foreach ( $order as $i ) { |
67 | | - $res->seek( $i ); |
68 | | - echo $res->fetchObject()->vote_record . "\n\n"; |
| 52 | + if ( !$this->headersSent ) { |
| 53 | + $this->sendHeaders(); |
69 | 54 | } |
70 | | - $this->closeRandom(); |
| 55 | + echo "</election>\n</SecurePoll>\n"; |
71 | 56 | } |
72 | 57 | |
73 | | - /** |
74 | | - * Open the /dev/urandom device |
75 | | - * @return bool success |
76 | | - */ |
77 | | - function openRandom() { |
78 | | - if ( wfIsWindows() ) { |
79 | | - return false; |
| 58 | + function dumpVote( $election, $row ) { |
| 59 | + if ( !$this->headersSent ) { |
| 60 | + $this->sendHeaders(); |
80 | 61 | } |
81 | | - $this->urandom = fopen( '/dev/urandom', 'rb' ); |
82 | | - if ( !$this->urandom ) { |
83 | | - return false; |
84 | | - } |
85 | | - return true; |
| 62 | + echo "<vote>" . $row->vote_record . "</vote>\n"; |
86 | 63 | } |
87 | 64 | |
88 | | - /** |
89 | | - * Close the urandom device |
90 | | - */ |
91 | | - function closeRandom() { |
92 | | - fclose( $this->urandom ); |
93 | | - } |
| 65 | + function sendHeaders() { |
| 66 | + global $wgOut; |
94 | 67 | |
95 | | - /** |
96 | | - * Get a random integer between 0 and ($maxp1 - 1) |
97 | | - */ |
98 | | - function random( $maxp1 ) { |
99 | | - $numBytes = ceil( strlen( base_convert( $maxp1, 10, 16 ) ) / 2 ); |
100 | | - if ( $numBytes == 0 ) { |
101 | | - return 0; |
102 | | - } |
103 | | - $data = fread( $this->urandom, $numBytes ); |
104 | | - if ( strlen( $data ) != $numBytes ) { |
105 | | - throw new MWException( __METHOD__.': not enough bytes' ); |
106 | | - } |
107 | | - $x = 0; |
108 | | - for ( $i = 0; $i < $numBytes; $i++ ) { |
109 | | - $x *= 256; |
110 | | - $x += ord( substr( $data, $i, 1 ) ); |
111 | | - } |
112 | | - return $x % $maxp1; |
| 68 | + $this->headersSent = true; |
| 69 | + $wgOut->disable(); |
| 70 | + header( 'Content-Type: application/vnd.mediawiki.securepoll' ); |
| 71 | + $electionId = $this->election->getId(); |
| 72 | + $filename = urlencode( "$electionId-" . wfTimestampNow() . '.securepoll' ); |
| 73 | + header( "Content-Disposition: attachment; filename=$filename" ); |
| 74 | + echo "<SecurePoll>\n<election>\n" . |
| 75 | + $this->election->getConfXml(); |
| 76 | + $this->context->setLanguages( array( $this->election->getLanguage() ) ); |
113 | 77 | } |
114 | | - |
115 | | - /** |
116 | | - * Works like shuffle() except more secure. Returns the new array instead |
117 | | - * of modifying it. The algorithm is the Knuth/Durstenfeld kind. |
118 | | - */ |
119 | | - function shuffle( $a ) { |
120 | | - $a = array_values( $a ); |
121 | | - for ( $i = count( $a ) - 1; $i >= 0; $i-- ) { |
122 | | - $target = $this->random( $i + 1 ); |
123 | | - $tmp = $a[$i]; |
124 | | - $a[$i] = $a[$target]; |
125 | | - $a[$target] = $tmp; |
126 | | - } |
127 | | - return $a; |
128 | | - } |
129 | 78 | } |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Election.php |
— | — | @@ -56,34 +56,34 @@ |
57 | 57 | var $title, $ballotType, $tallyType, $primaryLang, $startDate, $endDate, $authType; |
58 | 58 | |
59 | 59 | /** |
60 | | - * Constructor. |
| 60 | + * Constructor. |
| 61 | + * |
| 62 | + * Do not use this constructor directly, instead use SecurePoll_Context::getElection(). |
| 63 | + * |
61 | 64 | * @param $id integer |
62 | 65 | */ |
63 | | - function __construct( $id ) { |
64 | | - parent::__construct( 'election', $id ); |
| 66 | + function __construct( $context, $info ) { |
| 67 | + parent::__construct( $context, 'election', $info ); |
| 68 | + $this->title = $info['title']; |
| 69 | + $this->ballotType = $info['ballot']; |
| 70 | + $this->tallyType = $info['tally']; |
| 71 | + $this->primaryLang = $info['primaryLang']; |
| 72 | + $this->startDate = $info['startDate']; |
| 73 | + $this->endDate = $info['endDate']; |
| 74 | + $this->authType = $info['auth']; |
65 | 75 | } |
66 | 76 | |
67 | 77 | /** |
68 | | - * Create an object based on a DB result row. |
69 | | - * @param $row object |
70 | | - */ |
71 | | - static function newFromRow( $row ) { |
72 | | - $election = new self( $row->el_entity ); |
73 | | - $election->title = $row->el_title; |
74 | | - $election->ballotType = $row->el_ballot; |
75 | | - $election->tallyType = $row->el_tally; |
76 | | - $election->primaryLang = $row->el_primary_lang; |
77 | | - $election->startDate = $row->el_start_date; |
78 | | - $election->endDate = $row->el_end_date; |
79 | | - $election->authType = $row->el_auth_type; |
80 | | - return $election; |
81 | | - } |
82 | | - |
83 | | - /** |
84 | 78 | * Get a list of localisable message names. See SecurePoll_Entity. |
85 | 79 | */ |
86 | 80 | function getMessageNames() { |
87 | | - return array( 'title', 'intro', 'jump-text', 'return-text' ); |
| 81 | + return array( |
| 82 | + 'title', |
| 83 | + 'intro', |
| 84 | + 'jump-text', |
| 85 | + 'return-text', |
| 86 | + 'unqualified-error', |
| 87 | + ); |
88 | 88 | } |
89 | 89 | |
90 | 90 | /** |
— | — | @@ -131,7 +131,7 @@ |
132 | 132 | */ |
133 | 133 | function getBallot() { |
134 | 134 | if ( !$this->ballot ) { |
135 | | - $this->ballot = SecurePoll_Ballot::factory( $this->ballotType, $this ); |
| 135 | + $this->ballot = $this->context->newBallot( $this->ballotType, $this ); |
136 | 136 | } |
137 | 137 | return $this->ballot; |
138 | 138 | } |
— | — | @@ -180,6 +180,14 @@ |
181 | 181 | if ( $needList && !in_array( $needList, $lists ) ) { |
182 | 182 | $status->fatal( 'securepoll-not-in-list' ); |
183 | 183 | } |
| 184 | + |
| 185 | + # Get custom error message |
| 186 | + if ( !$status->isOK() ) { |
| 187 | + $errorMsg = $this->getMessage( 'unqualified-error' ); |
| 188 | + if ( $errorMsg !== '[unqualified-error]' && $errorMsg !== '' ) { |
| 189 | + $status = Status::newFatal( 'securepoll-custom-unqualified', $errorMsg ); |
| 190 | + } |
| 191 | + } |
184 | 192 | return $status; |
185 | 193 | } |
186 | 194 | |
— | — | @@ -187,7 +195,7 @@ |
188 | 196 | * Returns true if the user is an admin of the current election. |
189 | 197 | * @param $user User |
190 | 198 | */ |
191 | | - function isAdmin( User $user ) { |
| 199 | + function isAdmin( $user ) { |
192 | 200 | $admins = array_map( 'trim', explode( '|', $this->getProperty( 'admins' ) ) ); |
193 | 201 | return in_array( $user->getName(), $admins ); |
194 | 202 | } |
— | — | @@ -197,7 +205,7 @@ |
198 | 206 | * @param $voter SecurePoll_Voter |
199 | 207 | */ |
200 | 208 | function hasVoted( $voter ) { |
201 | | - $db = wfGetDB( DB_MASTER ); |
| 209 | + $db = $this->context->getDB(); |
202 | 210 | $row = $db->selectRow( |
203 | 211 | 'securepoll_votes', |
204 | 212 | array( "1" ), |
— | — | @@ -224,33 +232,11 @@ |
225 | 233 | */ |
226 | 234 | function getQuestions() { |
227 | 235 | if ( $this->questions === null ) { |
228 | | - $db = wfGetDB( DB_MASTER ); |
229 | | - $res = $db->select( |
230 | | - array( 'securepoll_questions', 'securepoll_options' ), |
231 | | - '*', |
232 | | - array( |
233 | | - 'qu_election' => $this->getId(), |
234 | | - 'op_question=qu_entity' |
235 | | - ), |
236 | | - __METHOD__, |
237 | | - array( 'ORDER BY' => 'qu_index, qu_entity' ) |
238 | | - ); |
239 | | - |
| 236 | + $info = $this->context->getStore()->getQuestionInfo( $this->getId() ); |
240 | 237 | $this->questions = array(); |
241 | | - $options = array(); |
242 | | - $questionId = false; |
243 | | - foreach ( $res as $row ) { |
244 | | - if ( $questionId === false ) { |
245 | | - } elseif ( $questionId !== $row->qu_entity ) { |
246 | | - $this->questions[] = new SecurePoll_Question( $questionId, $options ); |
247 | | - $options = array(); |
248 | | - } |
249 | | - $options[] = SecurePoll_Option::newFromRow( $row ); |
250 | | - $questionId = $row->qu_entity; |
| 238 | + foreach ( $info as $questionInfo ) { |
| 239 | + $this->questions[] = $this->context->newQuestion( $questionInfo ); |
251 | 240 | } |
252 | | - if ( $questionId !== false ) { |
253 | | - $this->questions[] = new SecurePoll_Question( $questionId, $options ); |
254 | | - } |
255 | 241 | } |
256 | 242 | return $this->questions; |
257 | 243 | } |
— | — | @@ -261,7 +247,7 @@ |
262 | 248 | */ |
263 | 249 | function getAuth() { |
264 | 250 | if ( !$this->auth ) { |
265 | | - $this->auth = SecurePoll_Auth::factory( $this->authType ); |
| 251 | + $this->auth = $this->context->newAuth( $this->authType ); |
266 | 252 | } |
267 | 253 | return $this->auth; |
268 | 254 | } |
— | — | @@ -285,7 +271,7 @@ |
286 | 272 | if ( $type === false || $type === 'none' ) { |
287 | 273 | return false; |
288 | 274 | } |
289 | | - $crypt = SecurePoll_Crypt::factory( $type, $this ); |
| 275 | + $crypt = $this->context->newCrypt( $type, $this ); |
290 | 276 | if ( !$crypt ) { |
291 | 277 | throw new MWException( 'Invalid encryption type' ); |
292 | 278 | } |
— | — | @@ -293,16 +279,112 @@ |
294 | 280 | } |
295 | 281 | |
296 | 282 | /** |
297 | | - * Get the tallier object |
298 | | - * @return SecurePoll_Tallier |
| 283 | + * Get the tally type |
299 | 284 | */ |
300 | | - function getTallier() { |
301 | | - $tallier = SecurePoll_Tallier::factory( $this->tallyType, $this ); |
302 | | - if ( !$tallier ) { |
303 | | - throw new MWException( 'Invalid tally type' ); |
| 285 | + function getTallyType() { |
| 286 | + return $this->tallyType; |
| 287 | + } |
| 288 | + |
| 289 | + /** |
| 290 | + * Call a callback function for each valid vote record, in random order. |
| 291 | + */ |
| 292 | + function dumpVotesToCallback( $callback ) { |
| 293 | + if ( !$this->getCrypt() ) { |
| 294 | + return Status::newFatal( 'securepoll-dump-no-crypt' ); |
304 | 295 | } |
305 | | - return $tallier; |
| 296 | + |
| 297 | + $random = $this->context->getRandom(); |
| 298 | + $status = $random->open(); |
| 299 | + if ( !$status->isOK() ) { |
| 300 | + return $status; |
| 301 | + } |
| 302 | + $db = $this->context->getDB(); |
| 303 | + $res = $db->select( |
| 304 | + 'securepoll_votes', |
| 305 | + array( '*' ), |
| 306 | + array( |
| 307 | + 'vote_election' => $this->getId(), |
| 308 | + 'vote_current' => 1, |
| 309 | + 'vote_struck' => 0 |
| 310 | + ), |
| 311 | + __METHOD__ |
| 312 | + ); |
| 313 | + if ( $res->numRows() ) { |
| 314 | + $order = $random->shuffle( range( 0, $res->numRows() - 1 ) ); |
| 315 | + foreach ( $order as $i ) { |
| 316 | + $res->seek( $i ); |
| 317 | + call_user_func( $callback, $this, $res->fetchObject() ); |
| 318 | + } |
| 319 | + } |
| 320 | + $random->close(); |
| 321 | + return Status::newGood(); |
306 | 322 | } |
307 | 323 | |
| 324 | + /** |
| 325 | + * Get an XML snippet describing the configuration of this object |
| 326 | + */ |
| 327 | + function getConfXml( $options = array() ) { |
| 328 | + $s = "<configuration>\n" . |
| 329 | + Xml::element( 'title', array(), $this->title ) . "\n" . |
| 330 | + Xml::element( 'ballot', array(), $this->ballotType ) . "\n" . |
| 331 | + Xml::element( 'tally', array(), $this->tallyType ) . "\n" . |
| 332 | + Xml::element( 'primaryLang', array(), $this->primaryLang ) . "\n" . |
| 333 | + Xml::element( 'startDate', array(), wfTimestamp( TS_ISO_8601, $this->startDate ) ) . "\n" . |
| 334 | + Xml::element( 'endDate', array(), wfTimestamp( TS_ISO_8601, $this->endDate ) ) . "\n" . |
| 335 | + $this->getConfXmlEntityStuff( $options ); |
| 336 | + |
| 337 | + # If we're making a jump dump, we need to add some extra properties, and |
| 338 | + # override the auth type |
| 339 | + if ( !empty( $options['jump'] ) ) { |
| 340 | + $s .= |
| 341 | + Xml::element( 'auth', array(), 'local' ) . "\n" . |
| 342 | + Xml::element( 'property', |
| 343 | + array( 'name' => 'jump-url' ), |
| 344 | + $this->context->getSpecialTitle()->getFullURL() |
| 345 | + ) . "\n" . |
| 346 | + Xml::element( 'property', |
| 347 | + array( 'name' => 'jump-id' ), |
| 348 | + $this->getId() |
| 349 | + ) . "\n"; |
| 350 | + } else { |
| 351 | + $s .= Xml::element( 'auth', array(), $this->authType ) . "\n"; |
| 352 | + } |
| 353 | + |
| 354 | + foreach ( $this->getQuestions() as $question ) { |
| 355 | + $s .= $question->getConfXml( $options ); |
| 356 | + } |
| 357 | + $s .= "</configuration>\n"; |
| 358 | + return $s; |
| 359 | + } |
| 360 | + |
| 361 | + /** |
| 362 | + * Get property names which aren't included in an XML dump |
| 363 | + */ |
| 364 | + function getPropertyDumpBlacklist( $options = array() ) { |
| 365 | + if ( !empty( $options['jump'] ) ) { |
| 366 | + return array( |
| 367 | + 'gpg-encrypt-key', |
| 368 | + 'gpg-sign-key', |
| 369 | + 'gpg-decrypt-key' |
| 370 | + ); |
| 371 | + } else { |
| 372 | + return array(); |
| 373 | + } |
| 374 | + } |
| 375 | + |
| 376 | + /** |
| 377 | + * Tally the valid votes for this election. |
| 378 | + * Returns a Status object. On success, the value property will contain a |
| 379 | + * SecurePoll_ElectionTallier object. |
| 380 | + */ |
| 381 | + function tally() { |
| 382 | + $tallier = $this->context->newElectionTallier( $this ); |
| 383 | + $status = $tallier->execute(); |
| 384 | + if ( $status->isOK() ) { |
| 385 | + return Status::newGood( $tallier ); |
| 386 | + } else { |
| 387 | + return $status; |
| 388 | + } |
| 389 | + } |
308 | 390 | } |
309 | 391 | |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/LoginPage.php |
— | — | @@ -14,7 +14,7 @@ |
15 | 15 | } |
16 | 16 | |
17 | 17 | $electionId = intval( $params[0] ); |
18 | | - $this->election = $this->parent->getElection( $electionId ); |
| 18 | + $this->election = $this->context->getElection( $electionId ); |
19 | 19 | if ( !$this->election ) { |
20 | 20 | $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId ); |
21 | 21 | return; |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Question.php |
— | — | @@ -9,12 +9,15 @@ |
10 | 10 | |
11 | 11 | /** |
12 | 12 | * Constructor |
13 | | - * @param $id integer |
14 | | - * @param $options array Array of SecurePoll_Option children |
| 13 | + * @param $context SecurePoll_Context |
| 14 | + * @param $info Associative array of entity info |
15 | 15 | */ |
16 | | - function __construct( $id, $options ) { |
17 | | - parent::__construct( 'question', $id ); |
18 | | - $this->options = $options; |
| 16 | + function __construct( $context, $info ) { |
| 17 | + parent::__construct( $context, 'question', $info ); |
| 18 | + $this->options = array(); |
| 19 | + foreach ( $info['options'] as $optionInfo ) { |
| 20 | + $this->options[] = new SecurePoll_Option( $context, $optionInfo ); |
| 21 | + } |
19 | 22 | } |
20 | 23 | |
21 | 24 | /** |
— | — | @@ -31,5 +34,16 @@ |
32 | 35 | return $this->options; |
33 | 36 | } |
34 | 37 | |
35 | | - function getOptions() { return $this->options; } |
| 38 | + function getOptions() { |
| 39 | + return $this->options; |
| 40 | + } |
| 41 | + |
| 42 | + function getConfXml( $options = array() ) { |
| 43 | + $s = "<question>\n" . $this->getConfXmlEntityStuff( $options ); |
| 44 | + foreach ( $this->getOptions() as $option ) { |
| 45 | + $s .= $option->getConfXml( $options ); |
| 46 | + } |
| 47 | + $s .= "</question>\n"; |
| 48 | + return $s; |
| 49 | + } |
36 | 50 | } |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/MessageDumpPage.php |
— | — | @@ -10,7 +10,7 @@ |
11 | 11 | } |
12 | 12 | |
13 | 13 | $electionId = intval( $params[0] ); |
14 | | - $this->election = $this->parent->getElection( $electionId ); |
| 14 | + $this->election = $this->context->getElection( $electionId ); |
15 | 15 | if ( !$this->election ) { |
16 | 16 | $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId ); |
17 | 17 | return; |
— | — | @@ -18,9 +18,9 @@ |
19 | 19 | |
20 | 20 | $wgOut->disable(); |
21 | 21 | header( 'Content-Type: application/x-sql; charset=utf-8' ); |
22 | | - $filename = urlencode( "sp-msgs-$electionId-" . wfTimestampNow() ); |
| 22 | + $filename = urlencode( "sp-msgs-$electionId-" . wfTimestampNow() . '.sql' ); |
23 | 23 | header( "Content-Disposition: attachment; filename=$filename" ); |
24 | | - $dbr = wfGetDB( DB_SLAVE ); |
| 24 | + $dbr = $this->context->getDB(); |
25 | 25 | |
26 | 26 | $entities = array_merge( array( $this->election ), $this->election->getDescendants() ); |
27 | 27 | $ids = array(); |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/ListPage.php |
— | — | @@ -20,7 +20,7 @@ |
21 | 21 | } |
22 | 22 | |
23 | 23 | $electionId = intval( $params[0] ); |
24 | | - $this->election = $this->parent->getElection( $electionId ); |
| 24 | + $this->election = $this->context->getElection( $electionId ); |
25 | 25 | if ( !$this->election ) { |
26 | 26 | $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId ); |
27 | 27 | return; |
— | — | @@ -84,7 +84,7 @@ |
85 | 85 | */ |
86 | 86 | static function ajaxStrike( $action, $id, $reason ) { |
87 | 87 | wfLoadExtensionMessages( 'SecurePoll' ); |
88 | | - $db = wfGetDB( DB_MASTER ); |
| 88 | + $db = $this->context->getDB(); |
89 | 89 | $table = $db->tableName( 'securepoll_elections' ); |
90 | 90 | $row = $db->selectRow( |
91 | 91 | array( 'securepoll_votes', 'securepoll_elections' ), |
— | — | @@ -98,9 +98,9 @@ |
99 | 99 | 'message' => wfMsgHtml( 'securepoll-strike-nonexistent' ) |
100 | 100 | ) ); |
101 | 101 | } |
102 | | - $page = new SecurePollPage; |
| 102 | + $page = new SecurePoll_BasePage; |
103 | 103 | $subpage = new self( $page ); |
104 | | - $subpage->election = SecurePoll_Election::newFromRow( $row ); |
| 104 | + $subpage->election = $subpage->context->newElectionFromRow( $row ); |
105 | 105 | $status = $subpage->strike( $action, $id, $reason ); |
106 | 106 | if ( $status->isGood() ) { |
107 | 107 | return Xml::encodeJsVar( (object)array( 'status' => 'good' ) ); |
— | — | @@ -122,7 +122,7 @@ |
123 | 123 | */ |
124 | 124 | function strike( $action, $voteId, $reason ) { |
125 | 125 | global $wgUser; |
126 | | - $dbw = wfGetDB( DB_MASTER ); |
| 126 | + $dbw = $this->context->getDB(); |
127 | 127 | if ( !$this->election->isAdmin( $wgUser ) ) { |
128 | 128 | return Status::newFatal( 'securepoll-need-admin' ); |
129 | 129 | } |
— | — | @@ -220,7 +220,7 @@ |
221 | 221 | function formatValue( $name, $value ) { |
222 | 222 | global $wgLang; |
223 | 223 | $critical = Xml::element( 'img', |
224 | | - array( 'src' => $GLOBALS['wgStylePath'] . '/common/images/critical-32.png' ) |
| 224 | + array( 'src' => $GLOBALS['wgScriptPath'] . '/extensions/SecurePoll/resources/critical-32.png' ) |
225 | 225 | ); |
226 | 226 | |
227 | 227 | switch ( $name ) { |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Option.php |
— | — | @@ -6,22 +6,15 @@ |
7 | 7 | */ |
8 | 8 | class SecurePoll_Option extends SecurePoll_Entity { |
9 | 9 | /** |
10 | | - * Create a new option from a DB row |
11 | | - * @param $row object |
| 10 | + * Constructor |
| 11 | + * @param $context SecurePoll_Context |
| 12 | + * @param $info Associative array of entity info |
12 | 13 | */ |
13 | | - static function newFromRow( $row ) { |
14 | | - return new self( $row->op_entity ); |
| 14 | + function __construct( $context, $info ) { |
| 15 | + parent::__construct( $context, 'option', $info ); |
15 | 16 | } |
16 | 17 | |
17 | 18 | /** |
18 | | - * Constructor, from entity ID |
19 | | - * @param $id integer |
20 | | - */ |
21 | | - function __construct( $id ) { |
22 | | - parent::__construct( 'option', $id ); |
23 | | - } |
24 | | - |
25 | | - /** |
26 | 19 | * Get a list of localisable message names. This is used to provide the |
27 | 20 | * translate subpage with a list of messages to localise. |
28 | 21 | */ |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/VotePage.php |
— | — | @@ -19,7 +19,7 @@ |
20 | 20 | } |
21 | 21 | |
22 | 22 | $electionId = intval( $params[0] ); |
23 | | - $this->election = $this->parent->getElection( $electionId ); |
| 23 | + $this->election = $this->context->getElection( $electionId ); |
24 | 24 | if ( !$this->election ) { |
25 | 25 | $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId ); |
26 | 26 | return; |
— | — | @@ -160,7 +160,7 @@ |
161 | 161 | $encrypted = $status->value; |
162 | 162 | } |
163 | 163 | |
164 | | - $dbw = wfGetDB( DB_MASTER ); |
| 164 | + $dbw = $this->context->getDB(); |
165 | 165 | $dbw->begin(); |
166 | 166 | |
167 | 167 | # Mark previous votes as old |
— | — | @@ -236,6 +236,7 @@ |
237 | 237 | throw new MWException( 'Configuration error: no jump-id' ); |
238 | 238 | } |
239 | 239 | $url .= "/login/$id"; |
| 240 | + wfRunHooks( 'SecurePoll_JumpUrl', array( $this, &$url ) ); |
240 | 241 | $wgOut->addWikiText( $this->election->getMessage( 'jump-text' ) ); |
241 | 242 | $wgOut->addHTML( |
242 | 243 | Xml::openElement( 'form', array( 'action' => $url, 'method' => 'post' ) ) . |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Base.php |
— | — | @@ -0,0 +1,105 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class SecurePoll_BasePage extends UnlistedSpecialPage { |
| 5 | + static $pages = array( |
| 6 | + 'details' => 'SecurePoll_DetailsPage', |
| 7 | + 'dump' => 'SecurePoll_DumpPage', |
| 8 | + 'entry' => 'SecurePoll_EntryPage', |
| 9 | + 'list' => 'SecurePoll_ListPage', |
| 10 | + 'login' => 'SecurePoll_LoginPage', |
| 11 | + 'msgdump' => 'SecurePoll_MessageDumpPage', |
| 12 | + 'tally' => 'SecurePoll_TallyPage', |
| 13 | + 'translate' => 'SecurePoll_TranslatePage', |
| 14 | + 'vote' => 'SecurePoll_VotePage', |
| 15 | + ); |
| 16 | + |
| 17 | + var $sp_context; |
| 18 | + |
| 19 | + /** |
| 20 | + * Constructor |
| 21 | + */ |
| 22 | + public function __construct() { |
| 23 | + parent::__construct( 'SecurePoll' ); |
| 24 | + $this->sp_context = new SecurePoll_Context; |
| 25 | + } |
| 26 | + |
| 27 | + /** |
| 28 | + * Show the special page |
| 29 | + * |
| 30 | + * @param $paramString Mixed: parameter passed to the page or null |
| 31 | + */ |
| 32 | + public function execute( $paramString ) { |
| 33 | + global $wgOut, $wgUser, $wgRequest, $wgScriptPath; |
| 34 | + |
| 35 | + wfLoadExtensionMessages( 'SecurePoll' ); |
| 36 | + |
| 37 | + $this->setHeaders(); |
| 38 | + $wgOut->addLink( array( |
| 39 | + 'rel' => 'stylesheet', |
| 40 | + 'href' => "$wgScriptPath/extensions/SecurePoll/resources/SecurePoll.css", |
| 41 | + 'type' => 'text/css' |
| 42 | + ) ); |
| 43 | + $wgOut->addScriptFile( "$wgScriptPath/extensions/SecurePoll/resources/SecurePoll.js" ); |
| 44 | + |
| 45 | + $this->request = $wgRequest; |
| 46 | + |
| 47 | + $paramString = strval( $paramString ); |
| 48 | + if ( $paramString === '' ) { |
| 49 | + $paramString = 'entry'; |
| 50 | + } |
| 51 | + $params = explode( '/', $paramString ); |
| 52 | + $pageName = array_shift( $params ); |
| 53 | + $page = $this->getSubpage( $pageName ); |
| 54 | + if ( !$page ) { |
| 55 | + $wgOut->addWikiMsg( 'securepoll-invalid-page', $pageName ); |
| 56 | + return; |
| 57 | + } |
| 58 | + |
| 59 | + if ( !($page instanceof SecurePoll_EntryPage ) ) { |
| 60 | + $this->setSubtitle(); |
| 61 | + } |
| 62 | + |
| 63 | + $page->execute( $params ); |
| 64 | + } |
| 65 | + |
| 66 | + /** |
| 67 | + * Get a SecurePoll_Page subclass object for the given subpage name |
| 68 | + */ |
| 69 | + function getSubpage( $name ) { |
| 70 | + if ( !isset( self::$pages[$name] ) ) { |
| 71 | + return false; |
| 72 | + } |
| 73 | + $className = self::$pages[$name]; |
| 74 | + $page = new $className( $this ); |
| 75 | + return $page; |
| 76 | + } |
| 77 | + |
| 78 | + /** |
| 79 | + * Get a random token for CSRF protection |
| 80 | + */ |
| 81 | + function getEditToken() { |
| 82 | + if ( !isset( $_SESSION['spToken'] ) ) { |
| 83 | + $_SESSION['spToken'] = sha1( mt_rand() . mt_rand() . mt_rand() ); |
| 84 | + } |
| 85 | + return $_SESSION['spToken']; |
| 86 | + } |
| 87 | + |
| 88 | + /** |
| 89 | + * Set a navigation subtitle. |
| 90 | + * Each argument is a two-element array giving a Title object to be used as |
| 91 | + * a link target, and the link text. |
| 92 | + */ |
| 93 | + function setSubtitle( /*...*/ ) { |
| 94 | + global $wgUser, $wgOut; |
| 95 | + $skin = $wgUser->getSkin(); |
| 96 | + $title = $this->getTitle(); |
| 97 | + $subtitle = '< ' . $skin->linkKnown( $title, htmlspecialchars( $title->getText() ) ); |
| 98 | + $pipe = wfMsg( 'pipe-separator' ); |
| 99 | + $links = func_get_args(); |
| 100 | + foreach ( $links as $link ) { |
| 101 | + list( $title, $text ) = $link; |
| 102 | + $subtitle .= $pipe . $skin->linkKnown( $title, htmlspecialchars( $text ) ); |
| 103 | + } |
| 104 | + $wgOut->setSubtitle( $subtitle ); |
| 105 | + } |
| 106 | +} |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/includes/Base.php |
___________________________________________________________________ |
Added: svn:mergeinfo |
Added: svn:eol-style |
1 | 107 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Entity.php |
— | — | @@ -12,21 +12,21 @@ |
13 | 13 | */ |
14 | 14 | class SecurePoll_Entity { |
15 | 15 | var $id; |
| 16 | + var $context; |
16 | 17 | var $messagesLoaded = array(); |
17 | 18 | var $properties; |
18 | 19 | |
19 | | - static $languages = array(); |
20 | | - static $messageCache = array(); |
21 | | - |
22 | 20 | /** |
23 | 21 | * Create an entity of the given type. This is typically called from the |
24 | 22 | * child constructor. |
| 23 | + * @param $context SecurePoll_Context |
25 | 24 | * @param $type string |
26 | | - * @param $id integer |
| 25 | + * @param $info Associative array of entity info |
27 | 26 | */ |
28 | | - function __construct( $type, $id = false ) { |
| 27 | + function __construct( $context, $type, $info ) { |
| 28 | + $this->context = $context; |
29 | 29 | $this->type = $type; |
30 | | - $this->id = $id; |
| 30 | + $this->id = isset( $info['id'] ) ? $info['id'] : false; |
31 | 31 | } |
32 | 32 | |
33 | 33 | /** |
— | — | @@ -54,17 +54,6 @@ |
55 | 55 | } |
56 | 56 | |
57 | 57 | /** |
58 | | - * Set the global language fallback sequence. |
59 | | - * |
60 | | - * @param $languages array A list of language codes. When a message is |
61 | | - * requested, the first code in the array will be tried first, followed |
62 | | - * by the subsequent codes. |
63 | | - */ |
64 | | - static function setLanguages( $languages ) { |
65 | | - self::$languages = $languages; |
66 | | - } |
67 | | - |
68 | | - /** |
69 | 58 | * Get the child entity objects. When the messages of an object are loaded, |
70 | 59 | * the messages of the children are loaded automatically, to reduce the |
71 | 60 | * query count. |
— | — | @@ -96,32 +85,13 @@ |
97 | 86 | */ |
98 | 87 | function loadMessages( $lang = false ) { |
99 | 88 | if ( $lang === false ) { |
100 | | - $lang = reset( self::$languages ); |
| 89 | + $lang = reset( $this->context->languages ); |
101 | 90 | } |
102 | 91 | $ids = array( $this->getId() ); |
103 | 92 | foreach ( $this->getDescendants() as $child ) { |
104 | | - $id = $child->getId(); |
105 | | - if ( !isset( self::$messageCache[$lang][$id] ) ) { |
106 | | - $ids[] = $id; |
107 | | - } |
| 93 | + $ids[] = $child->getId(); |
108 | 94 | } |
109 | | - if ( !count( $ids ) ) { |
110 | | - return; |
111 | | - } |
112 | | - |
113 | | - $db = wfGetDB( DB_MASTER ); |
114 | | - $res = $db->select( |
115 | | - 'securepoll_msgs', |
116 | | - '*', |
117 | | - array( |
118 | | - 'msg_entity' => $ids, |
119 | | - 'msg_lang' => $lang |
120 | | - ), |
121 | | - __METHOD__ |
122 | | - ); |
123 | | - foreach ( $res as $row ) { |
124 | | - self::$messageCache[$row->msg_lang][$row->msg_entity][$row->msg_key] = $row->msg_text; |
125 | | - } |
| 95 | + $this->context->getMessages( $lang, $ids ); |
126 | 96 | $this->messagesLoaded[$lang] = true; |
127 | 97 | } |
128 | 98 | |
— | — | @@ -131,15 +101,11 @@ |
132 | 102 | * automatically. |
133 | 103 | */ |
134 | 104 | function loadProperties() { |
135 | | - $db = wfGetDB( DB_MASTER ); |
136 | | - $res = $db->select( |
137 | | - 'securepoll_properties', |
138 | | - '*', |
139 | | - array( 'pr_entity' => $this->getId() ), |
140 | | - __METHOD__ ); |
141 | | - $this->properties = array(); |
142 | | - foreach ( $res as $row ) { |
143 | | - $this->properties[$row->pr_key] = $row->pr_value; |
| 105 | + $properties = $this->context->getStore()->getProperties( array( $this->getId() ) ); |
| 106 | + if ( count( $properties ) ) { |
| 107 | + $this->properties = reset( $properties ); |
| 108 | + } else { |
| 109 | + $this->properties = array(); |
144 | 110 | } |
145 | 111 | } |
146 | 112 | |
— | — | @@ -154,11 +120,7 @@ |
155 | 121 | if ( empty( $this->messagesLoaded[$language] ) ) { |
156 | 122 | $this->loadMessages( $language ); |
157 | 123 | } |
158 | | - if ( !isset( self::$messageCache[$language][$this->getId()][$name] ) ) { |
159 | | - return false; |
160 | | - } else { |
161 | | - return self::$messageCache[$language][$this->getId()][$name]; |
162 | | - } |
| 124 | + return $this->context->getMessage( $language, $this->getId(), $name ); |
163 | 125 | } |
164 | 126 | |
165 | 127 | /** |
— | — | @@ -170,18 +132,54 @@ |
171 | 133 | */ |
172 | 134 | function getMessage( $name ) { |
173 | 135 | $id = $this->getId(); |
174 | | - foreach ( self::$languages as $language ) { |
| 136 | + foreach ( $this->context->languages as $language ) { |
175 | 137 | if ( empty( $this->messagesLoaded[$language] ) ) { |
176 | 138 | $this->loadMessages( $language ); |
177 | 139 | } |
178 | | - if ( isset( self::$messageCache[$language][$id][$name] ) ) { |
179 | | - return self::$messageCache[$language][$id][$name]; |
| 140 | + $message = $this->getRawMessage( $name, $language ); |
| 141 | + if ( $message !== false ) { |
| 142 | + return $message; |
180 | 143 | } |
181 | 144 | } |
182 | 145 | return "[$name]"; |
183 | 146 | } |
184 | 147 | |
185 | 148 | /** |
| 149 | + * Get a message, and interpret it as wikitext, converting it to HTML. |
| 150 | + */ |
| 151 | + function parseMessage( $name, $lineStart = true ) { |
| 152 | + global $wgParser, $wgTitle; |
| 153 | + $parserOptions = $this->context->getParserOptions(); |
| 154 | + if ( $wgTitle ) { |
| 155 | + $title = $wgTitle; |
| 156 | + } else { |
| 157 | + $title = SpecialPage::getTitleFor( 'SecurePoll' ); |
| 158 | + } |
| 159 | + $wikiText = $this->getMessage( $name ); |
| 160 | + $out = $wgParser->parse( $wikiText, $title, $parserOptions, $lineStart ); |
| 161 | + return $out->getText(); |
| 162 | + } |
| 163 | + |
| 164 | + /** |
| 165 | + * Get a message and convert it from wikitext to HTML, without <p> tags. |
| 166 | + */ |
| 167 | + function parseMessageInline( $name ) { |
| 168 | + return $this->parseMessage( $name, false ); |
| 169 | + } |
| 170 | + |
| 171 | + /** |
| 172 | + * Get a list of languages for which we have translations, for this entity |
| 173 | + * and its descendants. |
| 174 | + */ |
| 175 | + function getLangList() { |
| 176 | + $ids = array( $this->getId() ); |
| 177 | + foreach ( $this->getDescendants() as $child ) { |
| 178 | + $ids[] = $child->getId(); |
| 179 | + } |
| 180 | + return $this->context->getStore()->getLangList( $ids ); |
| 181 | + } |
| 182 | + |
| 183 | + /** |
186 | 184 | * Get a property value. If it does not exist, the $default parameter |
187 | 185 | * is passed back. |
188 | 186 | * @param $name string |
— | — | @@ -198,4 +196,62 @@ |
199 | 197 | } |
200 | 198 | } |
201 | 199 | |
| 200 | + /** |
| 201 | + * Get all defined properties as an associative array |
| 202 | + */ |
| 203 | + function getAllProperties() { |
| 204 | + if ( $this->properties === null ) { |
| 205 | + $this->loadProperties(); |
| 206 | + } |
| 207 | + return $this->properties; |
| 208 | + } |
| 209 | + |
| 210 | + /** |
| 211 | + * Get configuration XML. Overridden by most subclasses. |
| 212 | + */ |
| 213 | + function getConfXml( $options = array() ) { |
| 214 | + return "<{$this->type}>\n" . |
| 215 | + $this->getConfXmlEntityStuff( $options ) . |
| 216 | + "</{$this->type}>\n"; |
| 217 | + } |
| 218 | + |
| 219 | + /** |
| 220 | + * Get an XML snippet giving the messages and properties |
| 221 | + */ |
| 222 | + function getConfXmlEntityStuff( $options = array() ) { |
| 223 | + $s = Xml::element( 'id', array(), $this->getId() ) . "\n"; |
| 224 | + $blacklist = $this->getPropertyDumpBlacklist( $options ); |
| 225 | + foreach ( $this->getAllProperties() as $name => $value ) { |
| 226 | + if ( !in_array( $name, $blacklist ) ) { |
| 227 | + $s .= Xml::element( 'property', array( 'name' => $name ), $value ) . "\n"; |
| 228 | + } |
| 229 | + } |
| 230 | + if ( isset( $options['langs'] ) ) { |
| 231 | + $langs = $options['langs']; |
| 232 | + } else { |
| 233 | + $langs = $this->context->languages; |
| 234 | + } |
| 235 | + foreach ( $this->getMessageNames() as $name ) { |
| 236 | + foreach ( $langs as $lang ) { |
| 237 | + $value = $this->getRawMessage( $name, $lang ); |
| 238 | + if ( $value !== false ) { |
| 239 | + $s .= Xml::element( |
| 240 | + 'message', |
| 241 | + array( 'name' => $name, 'lang' => $lang ), |
| 242 | + $value |
| 243 | + ) . "\n"; |
| 244 | + } |
| 245 | + } |
| 246 | + } |
| 247 | + return $s; |
| 248 | + } |
| 249 | + |
| 250 | + /** |
| 251 | + * Get property names which aren't included in an XML dump. |
| 252 | + * Overloaded by Election. |
| 253 | + */ |
| 254 | + function getPropertyDumpBlacklist( $options = array() ) { |
| 255 | + return array(); |
| 256 | + } |
| 257 | + |
202 | 258 | } |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Page.php |
— | — | @@ -5,6 +5,7 @@ |
6 | 6 | */ |
7 | 7 | abstract class SecurePoll_Page { |
8 | 8 | var $parent, $election, $auth, $user; |
| 9 | + var $context; |
9 | 10 | |
10 | 11 | /** |
11 | 12 | * Constructor. |
— | — | @@ -12,6 +13,7 @@ |
13 | 14 | */ |
14 | 15 | function __construct( $parent ) { |
15 | 16 | $this->parent = $parent; |
| 17 | + $this->context = $parent->sp_context; |
16 | 18 | } |
17 | 19 | |
18 | 20 | /** |
— | — | @@ -48,6 +50,6 @@ |
49 | 51 | if ( $fallback != 'en' ) { |
50 | 52 | $languages[] = 'en'; |
51 | 53 | } |
52 | | - SecurePoll_Entity::setLanguages( $languages ); |
| 54 | + $this->context->setLanguages( $languages ); |
53 | 55 | } |
54 | 56 | } |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Ballot.php |
— | — | @@ -4,7 +4,7 @@ |
5 | 5 | * Parent class for ballot forms. This is the UI component of a voting method. |
6 | 6 | */ |
7 | 7 | abstract class SecurePoll_Ballot { |
8 | | - var $election; |
| 8 | + var $election, $context; |
9 | 9 | |
10 | 10 | /** |
11 | 11 | * Get a list of names of tallying methods, which may be used to produce a |
— | — | @@ -14,11 +14,11 @@ |
15 | 15 | abstract function getTallyTypes(); |
16 | 16 | |
17 | 17 | /** |
18 | | - * Get the HTML for this ballot. <form> tags should not be included, |
19 | | - * they will be added by the VotePage. |
| 18 | + * Get the HTML form segment for a single question |
| 19 | + * @param $question SecurePoll_Question |
20 | 20 | * @return string |
21 | 21 | */ |
22 | | - abstract function getForm(); |
| 22 | + abstract function getQuestionForm( $question ); |
23 | 23 | |
24 | 24 | /** |
25 | 25 | * Called when the form is submitted. This returns a Status object which, |
— | — | @@ -35,17 +35,18 @@ |
36 | 36 | |
37 | 37 | /** |
38 | 38 | * Create a ballot of the given type |
| 39 | + * @param $context SecurePoll_Context |
39 | 40 | * @param $type string |
40 | 41 | * @param $election SecurePoll_Election |
41 | 42 | */ |
42 | | - static function factory( $type, $election ) { |
| 43 | + static function factory( $context, $type, $election ) { |
43 | 44 | switch ( $type ) { |
44 | 45 | case 'approval': |
45 | | - return new SecurePoll_ApprovalBallot( $election ); |
| 46 | + return new SecurePoll_ApprovalBallot( $context, $election ); |
46 | 47 | case 'preferential': |
47 | | - return new SecurePoll_PreferentialBallot( $election ); |
| 48 | + return new SecurePoll_PreferentialBallot( $context, $election ); |
48 | 49 | case 'choose': |
49 | | - return new SecurePoll_ChooseBallot( $election ); |
| 50 | + return new SecurePoll_ChooseBallot( $context, $election ); |
50 | 51 | default: |
51 | 52 | throw new MWException( "Invalid ballot type: $type" ); |
52 | 53 | } |
— | — | @@ -53,11 +54,35 @@ |
54 | 55 | |
55 | 56 | /** |
56 | 57 | * Constructor. |
| 58 | + * @param $context SecurePoll_Context |
57 | 59 | * @param $election SecurePoll_Election |
58 | 60 | */ |
59 | | - function __construct( $election ) { |
| 61 | + function __construct( $context, $election ) { |
| 62 | + $this->context = $context; |
60 | 63 | $this->election = $election; |
61 | 64 | } |
| 65 | + |
| 66 | + /** |
| 67 | + * Get the HTML for this ballot. <form> tags should not be included, |
| 68 | + * they will be added by the VotePage. |
| 69 | + * @return string |
| 70 | + */ |
| 71 | + function getForm() { |
| 72 | + global $wgParser, $wgTitle; |
| 73 | + $questions = $this->election->getQuestions(); |
| 74 | + if ( $this->election->getProperty( 'shuffle-questions' ) ) { |
| 75 | + shuffle( $questions ); |
| 76 | + } |
| 77 | + |
| 78 | + $s = ''; |
| 79 | + foreach ( $questions as $question ) { |
| 80 | + $s .= "<hr/>\n" . |
| 81 | + $question->parseMessage( 'text' ) . |
| 82 | + $this->getQuestionForm( $question ) . |
| 83 | + "\n"; |
| 84 | + } |
| 85 | + return $s; |
| 86 | + } |
62 | 87 | } |
63 | 88 | |
64 | 89 | /** |
— | — | @@ -79,37 +104,27 @@ |
80 | 105 | } |
81 | 106 | |
82 | 107 | /** |
83 | | - * Get the HTML for this ballot. |
| 108 | + * Get the HTML form segment for a single question |
| 109 | + * @param $question SecurePoll_Question |
84 | 110 | * @return string |
85 | 111 | */ |
86 | | - function getForm() { |
87 | | - global $wgParser, $wgTitle; |
88 | | - $questions = $this->election->getQuestions(); |
89 | | - if ( $this->election->getProperty( 'shuffle-questions' ) ) { |
90 | | - shuffle( $questions ); |
| 112 | + function getQuestionForm( $question ) { |
| 113 | + $options = $question->getChildren(); |
| 114 | + if ( $this->election->getProperty( 'shuffle-options' ) ) { |
| 115 | + shuffle( $options ); |
91 | 116 | } |
92 | | - |
| 117 | + $name = 'securepoll_q' . $question->getId(); |
93 | 118 | $s = ''; |
94 | | - $parserOpts = new ParserOptions; |
95 | | - |
96 | | - foreach ( $questions as $question ) { |
97 | | - $s .= "<hr/>\n"; |
98 | | - $s .= $wgParser->parse( $question->getMessage( 'text' ), $wgTitle, $parserOpts )->getText(); |
99 | | - $options = $question->getChildren(); |
100 | | - if ( $this->election->getProperty( 'shuffle-options' ) ) { |
101 | | - shuffle( $options ); |
102 | | - } |
103 | | - $name = 'securepoll_q' . $question->getId(); |
104 | | - foreach ( $options as $option ) { |
105 | | - $optionText = $option->getMessage( 'text' ); |
106 | | - $optionHTML = $wgParser->parse( $optionText, $wgTitle, $parserOpts, false )->getText(); |
107 | | - $optionId = $option->getId(); |
108 | | - $radioId = "{$name}_opt{$optionId}"; |
109 | | - $s .= Xml::radio( $name, $optionId, false, array( 'id' => $radioId ) ) . |
110 | | - ' ' . |
111 | | - Xml::tags( 'label', array( 'for' => $radioId ), $optionText ) . |
112 | | - "<br/>\n"; |
113 | | - } |
| 119 | + foreach ( $options as $option ) { |
| 120 | + $optionHTML = $option->parseMessageInline( 'text' ); |
| 121 | + $optionId = $option->getId(); |
| 122 | + $radioId = "{$name}_opt{$optionId}"; |
| 123 | + $s .= |
| 124 | + '<div class="securepoll-option-choose">' . |
| 125 | + Xml::radio( $name, $optionId, false, array( 'id' => $radioId ) ) . |
| 126 | + ' ' . |
| 127 | + Xml::tags( 'label', array( 'for' => $radioId ), $optionHTML ) . |
| 128 | + "</div>\n"; |
114 | 129 | } |
115 | 130 | return $s; |
116 | 131 | } |
— | — | @@ -154,61 +169,100 @@ |
155 | 170 | } |
156 | 171 | |
157 | 172 | /** |
158 | | - * TODO: this is code copied directly from BoardVote, it needs to be ported. |
| 173 | + * Ballot for preferential voting |
| 174 | + * Properties: |
| 175 | + * shuffle-questions |
| 176 | + * shuffle-options |
| 177 | + * must-rank-all |
159 | 178 | */ |
160 | 179 | class SecurePoll_PreferentialBallot extends SecurePoll_Ballot { |
161 | 180 | function getTallyTypes() { |
162 | | - return array( 'plurality', 'condorcet' ); |
| 181 | + return array( 'schulze' ); |
163 | 182 | } |
164 | 183 | |
165 | | - function getRecord() { |
166 | | - global $wgBoardCandidates; |
167 | | - |
168 | | - $record = "I prefer: "; |
169 | | - $num_candidates = count( $wgBoardCandidates ); |
170 | | - $cnt = 0; |
171 | | - foreach ( $this->mVotedFor as $i => $rank ) { |
172 | | - $cnt++; |
173 | | - |
174 | | - $record .= $wgBoardCandidates[ $i ] . "["; |
175 | | - $record .= ( $rank == '' ) ? 100 : $rank; |
176 | | - $record .= "]"; |
177 | | - $record .= ( $cnt != $num_candidates ) ? ", " : ""; |
| 184 | + function getQuestionForm( $question ) { |
| 185 | + global $wgRequest; |
| 186 | + $options = $question->getChildren(); |
| 187 | + if ( $this->election->getProperty( 'shuffle-options' ) ) { |
| 188 | + shuffle( $options ); |
178 | 189 | } |
179 | | - $record .= "\n"; |
| 190 | + $name = 'securepoll_q' . $question->getId(); |
| 191 | + $s = ''; |
| 192 | + foreach ( $options as $option ) { |
| 193 | + $optionHTML = $option->parseMessageInline( 'text' ); |
| 194 | + $optionId = $option->getId(); |
| 195 | + $inputId = "{$name}_opt{$optionId}"; |
| 196 | + $oldValue = $wgRequest->getVal( $inputId, '' ); |
| 197 | + $s .= |
| 198 | + '<div class="securepoll-option-preferential">' . |
| 199 | + Xml::input( $inputId, '3', $oldValue, array( |
| 200 | + 'id' => $inputId, |
| 201 | + 'maxlength' => 3, |
| 202 | + ) ) . |
| 203 | + ' ' . |
| 204 | + Xml::tags( 'label', array( 'for' => $inputId ), $optionHTML ) . |
| 205 | + ' ' . |
| 206 | + "</div>\n"; |
| 207 | + } |
| 208 | + return $s; |
| 209 | + } |
180 | 210 | |
181 | | - // Pad it out with spaces to a constant length, so that the encrypted record is secure |
182 | | - $padLength = array_sum( array_map( 'strlen', $wgBoardCandidates ) ) + $num_candidates * 8 + 20; |
183 | | - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ |
184 | | - // length of the candidate names added together room for rank & separators extra |
| 211 | + function submitForm() { |
| 212 | + global $wgRequest; |
| 213 | + $questions = $this->election->getQuestions(); |
| 214 | + $record = ''; |
| 215 | + $status = Status::newGood(); |
185 | 216 | |
186 | | - $record = str_pad( $record, $padLength ); |
187 | | - return $record; |
188 | | - } |
| 217 | + foreach ( $questions as $question ) { |
| 218 | + $options = $question->getOptions(); |
| 219 | + foreach ( $options as $option ) { |
| 220 | + $id = 'securepoll_q' . $question->getId() . '_opt' . $option->getId(); |
| 221 | + $rank = $wgRequest->getVal( $id ); |
189 | 222 | |
190 | | - function validVote() { |
191 | | - foreach ( $this->mVotedFor as $rank ) { |
192 | | - if ( $rank != '' ) { |
193 | | - if ( !preg_match( '/^[1-9]\d?$/', $rank ) ) { |
194 | | - return false; |
| 223 | + if ( is_numeric( $rank ) ) { |
| 224 | + if ( $rank <= 0 || $rank >= 1000 ) { |
| 225 | + $status->fatal( 'securepoll-invalid-rank', $id ); |
| 226 | + continue; |
| 227 | + } else { |
| 228 | + $rank = intval( $rank ); |
| 229 | + } |
| 230 | + } elseif ( strval( $rank ) === '' ) { |
| 231 | + if ( $this->election->getProperty( 'must-rank-all' ) ) { |
| 232 | + $status->fatal( 'securepoll-unranked-options', $id ); |
| 233 | + continue; |
| 234 | + } else { |
| 235 | + $rank = 1000; |
| 236 | + } |
| 237 | + } else { |
| 238 | + $status->fatal( 'securepoll-invalid-rank', $id ); |
| 239 | + continue; |
195 | 240 | } |
| 241 | + $record .= sprintf( 'Q%08X-A%08X-R%08X--', |
| 242 | + $question->getId(), $option->getId(), $rank ); |
196 | 243 | } |
197 | 244 | } |
198 | | - |
199 | | - return true; |
| 245 | + if ( $status->isOK() ) { |
| 246 | + $status->value = $record . "\n"; |
| 247 | + } |
| 248 | + return $status; |
200 | 249 | } |
201 | 250 | |
202 | | - function voteEntry( $index, $candidate ) { |
203 | | - return " |
204 | | - <tr><td align=\"right\"> |
205 | | - <input type=\"text\" maxlength=\"2\" size=\"2\" name=\"candidate[{$index}]\" /> |
206 | | - </td><td align=\"left\"> |
207 | | - $candidate |
208 | | - </td></tr>"; |
| 251 | + function unpackRecord( $record ) { |
| 252 | + $ranks = array(); |
| 253 | + $itemLength = 3*8 + 7; |
| 254 | + for ( $offset = 0; $offset < strlen( $record ); $offset += $itemLength ) { |
| 255 | + if ( !preg_match( '/Q([0-9A-F]{8})-A([0-9A-F]{8})-R([0-9A-F]{8})--/A', |
| 256 | + $record, $m, 0, $offset ) ) |
| 257 | + { |
| 258 | + wfDebug( __METHOD__.": regex doesn't match\n" ); |
| 259 | + return false; |
| 260 | + } |
| 261 | + $qid = intval( base_convert( $m[1], 16, 10 ) ); |
| 262 | + $oid = intval( base_convert( $m[2], 16, 10 ) ); |
| 263 | + $rank = intval( base_convert( $m[3], 16, 10 ) ); |
| 264 | + $ranks[$qid][$oid] = $rank; |
| 265 | + } |
| 266 | + return $ranks; |
209 | 267 | } |
210 | | - |
211 | | - function getForm() { } |
212 | | - function submitForm() { } |
213 | | - function unpackRecord( $record ) {} |
214 | 268 | } |
215 | 269 | |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/ElectionTallier.php |
— | — | @@ -0,0 +1,119 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * A helper class for tallying a whole election (with multiple questions). |
| 6 | + * Most of the functionality is contained in the SecurePoll_Tallier subclasses |
| 7 | + * which operate on a single question at a time. |
| 8 | + * |
| 9 | + * A convenience function for accessing this class is |
| 10 | + * SecurePoll_Election::tally(). |
| 11 | + */ |
| 12 | +class SecurePoll_ElectionTallier { |
| 13 | + /** |
| 14 | + * Constructor. |
| 15 | + * @param $context SecurePoll_Context |
| 16 | + * @param $election SecurePoll_Election |
| 17 | + */ |
| 18 | + function __construct( $context, $election ) { |
| 19 | + $this->context = $context; |
| 20 | + $this->election = $election; |
| 21 | + } |
| 22 | + |
| 23 | + /** |
| 24 | + * Do the tally. Returns a Status object. On success, the value property |
| 25 | + * of the status will be an array of SecurePoll_Tallier objects, which can |
| 26 | + * be queried for results information. |
| 27 | + */ |
| 28 | + function execute() { |
| 29 | + $store = $this->context->getStore(); |
| 30 | + $this->crypt = $this->election->getCrypt(); |
| 31 | + $this->ballot = $this->election->getBallot(); |
| 32 | + $questions = $this->election->getQuestions(); |
| 33 | + $this->talliers = array(); |
| 34 | + $tallyType = $this->election->getTallyType(); |
| 35 | + foreach ( $questions as $question ) { |
| 36 | + $tallier = $this->context->newTallier( $tallyType, $question ); |
| 37 | + if ( !$tallier ) { |
| 38 | + throw new MWException( 'Invalid tally type' ); |
| 39 | + } |
| 40 | + $this->talliers[$question->getId()] = $tallier; |
| 41 | + } |
| 42 | + |
| 43 | + $status = $store->callbackValidVotes( $this->election->getId(), array( $this, 'addRecord' ) ); |
| 44 | + if ( !$status->isOK() ) { |
| 45 | + return $status; |
| 46 | + } |
| 47 | + |
| 48 | + foreach ( $this->talliers as $tallier ) { |
| 49 | + $tallier->finishTally(); |
| 50 | + } |
| 51 | + return Status::newGood( $this->talliers ); |
| 52 | + } |
| 53 | + |
| 54 | + /** |
| 55 | + * Add a record. This is the callback function for SecurePoll_Store::callbackValidVotes(). |
| 56 | + * On error, the Status object returned here will be passed through back to |
| 57 | + * the caller of callbackValidVotes(). |
| 58 | + * |
| 59 | + * @param $store SecurePoll_Store |
| 60 | + * @param $record string Encrypted, packed record. |
| 61 | + * @return Status |
| 62 | + */ |
| 63 | + function addRecord( $store, $record ) { |
| 64 | + # Decrypt and unpack |
| 65 | + if ( $this->crypt ) { |
| 66 | + $status = $this->crypt->decrypt( $record ); |
| 67 | + if ( !$status->isOK() ) { |
| 68 | + return $status; |
| 69 | + } |
| 70 | + $record = $status->value; |
| 71 | + } |
| 72 | + $record = rtrim( $record ); |
| 73 | + $scores = $this->ballot->unpackRecord( $record ); |
| 74 | + |
| 75 | + # Add the record to the underlying question-specific tallier objects |
| 76 | + foreach ( $this->election->getQuestions() as $question ) { |
| 77 | + $qid = $question->getId(); |
| 78 | + if ( !isset( $scores[$qid] ) ) { |
| 79 | + return Status::newFatal( 'securepoll-tally-error' ); |
| 80 | + } |
| 81 | + if ( !$this->talliers[$qid]->addVote( $scores[$qid] ) ) { |
| 82 | + return Status::newFatal( 'securepoll-tally-error' ); |
| 83 | + } |
| 84 | + } |
| 85 | + return Status::newGood(); |
| 86 | + } |
| 87 | + |
| 88 | + /** |
| 89 | + * Get HTML formatted results for this tally. Should only be called after |
| 90 | + * execute(). |
| 91 | + */ |
| 92 | + function getHtmlResult() { |
| 93 | + $s = ''; |
| 94 | + foreach ( $this->election->getQuestions() as $question ) { |
| 95 | + if ( $s !== '' ) { |
| 96 | + $s .= "<hr/>\n"; |
| 97 | + } |
| 98 | + $tallier = $this->talliers[$question->getId()]; |
| 99 | + $s .= $tallier->getHtmlResult(); |
| 100 | + } |
| 101 | + return $s; |
| 102 | + } |
| 103 | + |
| 104 | + /** |
| 105 | + * Get text formatted results for this tally. Should only be called after |
| 106 | + * execute(). |
| 107 | + */ |
| 108 | + function getTextResult() { |
| 109 | + $s = ''; |
| 110 | + foreach ( $this->election->getQuestions() as $question ) { |
| 111 | + if ( $s !== '' ) { |
| 112 | + $s .= "\n"; |
| 113 | + } |
| 114 | + $tallier = $this->talliers[$question->getId()]; |
| 115 | + $s .= $tallier->getTextResult(); |
| 116 | + } |
| 117 | + return $s; |
| 118 | + } |
| 119 | +} |
| 120 | + |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/includes/ElectionTallier.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 121 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Random.php |
— | — | @@ -0,0 +1,70 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class SecurePoll_Random { |
| 5 | + var $urandom; |
| 6 | + |
| 7 | + /** |
| 8 | + * Open a /dev/urandom file handle |
| 9 | + * Returns a Status object |
| 10 | + */ |
| 11 | + function open() { |
| 12 | + if ( $this->urandom ) { |
| 13 | + return Status::newGood(); |
| 14 | + } |
| 15 | + |
| 16 | + if ( wfIsWindows() ) { |
| 17 | + return Status::newFatal( 'securepoll-urandom-not-supported' ); |
| 18 | + } |
| 19 | + $this->urandom = fopen( '/dev/urandom', 'rb' ); |
| 20 | + if ( !$this->urandom ) { |
| 21 | + return Status::newFatal( 'securepoll-dump-no-urandom' ); |
| 22 | + } |
| 23 | + return Status::newGood(); |
| 24 | + } |
| 25 | + |
| 26 | + /** |
| 27 | + * Close any open file handles |
| 28 | + */ |
| 29 | + function close() { |
| 30 | + if ( $this->urandom ) { |
| 31 | + fclose( $this->urandom ); |
| 32 | + $this->urandom = null; |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + /** |
| 37 | + * Get a random integer between 0 and ($maxp1 - 1). |
| 38 | + * Should only be called after open() succeeds. |
| 39 | + */ |
| 40 | + function getInt( $maxp1 ) { |
| 41 | + $numBytes = ceil( strlen( base_convert( $maxp1, 10, 16 ) ) / 2 ); |
| 42 | + if ( $numBytes == 0 ) { |
| 43 | + return 0; |
| 44 | + } |
| 45 | + $data = fread( $this->urandom, $numBytes ); |
| 46 | + if ( strlen( $data ) != $numBytes ) { |
| 47 | + throw new MWException( __METHOD__.': not enough bytes' ); |
| 48 | + } |
| 49 | + $x = 0; |
| 50 | + for ( $i = 0; $i < $numBytes; $i++ ) { |
| 51 | + $x *= 256; |
| 52 | + $x += ord( substr( $data, $i, 1 ) ); |
| 53 | + } |
| 54 | + return $x % $maxp1; |
| 55 | + } |
| 56 | + |
| 57 | + /** |
| 58 | + * Works like shuffle() except more secure. Returns the new array instead |
| 59 | + * of modifying it. The algorithm is the Knuth/Durstenfeld kind. |
| 60 | + */ |
| 61 | + function shuffle( $a ) { |
| 62 | + $a = array_values( $a ); |
| 63 | + for ( $i = count( $a ) - 1; $i >= 0; $i-- ) { |
| 64 | + $target = $this->getInt( $i + 1 ); |
| 65 | + $tmp = $a[$i]; |
| 66 | + $a[$i] = $a[$target]; |
| 67 | + $a[$target] = $tmp; |
| 68 | + } |
| 69 | + return $a; |
| 70 | + } |
| 71 | +} |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/includes/Random.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 72 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/DetailsPage.php |
— | — | @@ -17,7 +17,8 @@ |
18 | 18 | } |
19 | 19 | |
20 | 20 | $this->voteId = intval( $params[0] ); |
21 | | - $db = wfGetDB( DB_MASTER ); |
| 21 | + |
| 22 | + $db = $this->context->getDB(); |
22 | 23 | $row = $db->selectRow( |
23 | 24 | array( 'securepoll_votes', 'securepoll_elections', 'securepoll_voters' ), |
24 | 25 | '*', |
— | — | @@ -33,8 +34,13 @@ |
34 | 35 | return; |
35 | 36 | } |
36 | 37 | |
37 | | - $this->election = SecurePoll_Election::newFromRow( $row ); |
| 38 | + $this->election = $this->context->newElectionFromRow( $row ); |
38 | 39 | $this->initLanguage( $wgUser, $this->election ); |
| 40 | + |
| 41 | + $this->parent->setSubtitle( array( |
| 42 | + $this->parent->getTitle( 'list/' . $this->election->getId() ), |
| 43 | + wfMsg( 'securepoll-list-title', $this->election->getMessage( 'title' ) ) ) ); |
| 44 | + |
39 | 45 | if ( !$this->election->isAdmin( $wgUser ) ) { |
40 | 46 | $wgOut->addWikiMsg( 'securepoll-need-admin' ); |
41 | 47 | return; |
— | — | @@ -85,7 +91,7 @@ |
86 | 92 | $wgOut->addHTML( '<h2>' . wfMsgHTML( 'securepoll-cookie-dup-list' ) . '</h2>' ); |
87 | 93 | $wgOut->addHTML( '<table class="TablePager">' ); |
88 | 94 | foreach ( $res as $row ) { |
89 | | - $voter = SecurePoll_Voter::newFromId( $row->voter ); |
| 95 | + $voter = $this->context->getVoter( $row->voter ); |
90 | 96 | $wgOut->addHTML( |
91 | 97 | '<tr>' . |
92 | 98 | '<td>' . htmlspecialchars( $wgLang->timeanddate( $row->cm_timestamp ) ) . '</td>' . |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/TallyPage.php |
— | — | @@ -17,14 +17,13 @@ |
18 | 18 | } |
19 | 19 | |
20 | 20 | $electionId = intval( $params[0] ); |
21 | | - $this->election = $this->parent->getElection( $electionId ); |
| 21 | + $this->election = $this->context->getElection( $electionId ); |
22 | 22 | if ( !$this->election ) { |
23 | 23 | $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId ); |
24 | 24 | return; |
25 | 25 | } |
26 | 26 | $this->initLanguage( $wgUser, $this->election ); |
27 | 27 | $wgOut->setPageTitle( wfMsg( 'securepoll-tally-title', $this->election->getMessage( 'title' ) ) ); |
28 | | - |
29 | 28 | if ( !$this->election->isAdmin( $wgUser ) ) { |
30 | 29 | $wgOut->addWikiMsg( 'securepoll-need-admin' ); |
31 | 30 | return; |
— | — | @@ -125,30 +124,13 @@ |
126 | 125 | */ |
127 | 126 | function submitLocal() { |
128 | 127 | global $wgOut; |
129 | | - $dbr = wfGetDB( DB_SLAVE ); |
130 | | - $res = $dbr->select( |
131 | | - 'securepoll_votes', |
132 | | - array( 'vote_record' ), |
133 | | - array( |
134 | | - 'vote_election' => $this->election->getId(), |
135 | | - 'vote_current' => 1, |
136 | | - 'vote_struck' => 0 |
137 | | - ), __METHOD__ |
138 | | - ); |
139 | | - $crypt = $this->election->getCrypt(); |
140 | | - $tallier = $this->election->getTallier(); |
141 | | - foreach ( $res as $row ) { |
142 | | - $status = $crypt->decrypt( $row->vote_record ); |
143 | | - if ( !$status->isOK() ) { |
144 | | - $wgOut->addWikiText( $status->getWikiText() ); |
145 | | - return; |
146 | | - } |
147 | | - if ( !$tallier->addRecord( $status->value ) ) { |
148 | | - $wgOut->addWikiMsg( 'securepoll-tally-error' ); |
149 | | - return; |
150 | | - } |
| 128 | + $status = $this->election->tally(); |
| 129 | + if ( !$status->isOK() ) { |
| 130 | + $wgOut->addWikiText( $status->getWikiText() ); |
| 131 | + return; |
151 | 132 | } |
152 | | - $wgOut->addHTML( $tallier->getResult() ); |
| 133 | + $tallier = $status->value; |
| 134 | + $wgOut->addHTML( $tallier->getHtmlResult() ); |
153 | 135 | } |
154 | 136 | |
155 | 137 | /** |
— | — | @@ -156,8 +138,6 @@ |
157 | 139 | */ |
158 | 140 | function submitUpload() { |
159 | 141 | global $wgOut; |
160 | | - $crypt = $this->election->getCrypt(); |
161 | | - $tallier = $this->election->getTallier(); |
162 | 142 | if ( !isset( $_FILES['tally_file'] ) |
163 | 143 | || !is_uploaded_file( $_FILES['tally_file']['tmp_name'] ) |
164 | 144 | || !$_FILES['tally_file']['size'] ) |
— | — | @@ -165,24 +145,21 @@ |
166 | 146 | $wgOut->addWikiMsg( 'securepoll-no-upload' ); |
167 | 147 | return; |
168 | 148 | } |
169 | | - |
170 | | - $fileString = file_get_contents( $_FILES['tally_file']['tmp_name'] ); |
171 | | - $records = StringUtils::explode( "\n\n\n", $fileString ); |
172 | | - foreach ( $records as $encrypted ) { |
173 | | - if ( trim( $encrypted ) == '' ) { |
174 | | - continue; |
175 | | - } |
176 | | - $status = $crypt->decrypt( $encrypted ); |
177 | | - if ( !$status->isOK() ) { |
178 | | - $wgOut->addWikiText( $status->getWikiText() ); |
179 | | - return; |
180 | | - } |
181 | | - if ( !$tallier->addRecord( $status->value ) ) { |
182 | | - $wgOut->addWikiMsg( 'securepoll-tally-error' ); |
183 | | - return; |
184 | | - } |
| 149 | + $context = SecurePoll_Context::newFromXmlFile( $_FILES['tally_file']['tmp_name'] ); |
| 150 | + if ( !$context ) { |
| 151 | + $wgOut->addWikiMsg( 'securepoll-dump-corrupt' ); |
| 152 | + return; |
185 | 153 | } |
186 | | - $wgOut->addHTML( $tallier->getResult() ); |
| 154 | + $electionIds = $context->getStore()->getAllElectionIds(); |
| 155 | + $election = $context->getElection( reset( $electionIds ) ); |
| 156 | + |
| 157 | + $status = $election->tally(); |
| 158 | + if ( !$status->isOK() ) { |
| 159 | + $wgOut->addWikiText( $status->getWikiText( 'securepoll-tally-upload-error' ) ); |
| 160 | + return; |
| 161 | + } |
| 162 | + $tallier = $status->value; |
| 163 | + $wgOut->addHTML( $tallier->getHtmlResult() ); |
187 | 164 | } |
188 | 165 | |
189 | 166 | function getTitle() { |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Context.php |
— | — | @@ -0,0 +1,314 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * This object contains caches and various items of processing context for |
| 6 | + * SecurePoll. It manages instances of long-lived objects such as the |
| 7 | + * SecurePoll_Store subclass. |
| 8 | + * |
| 9 | + * Long-lived data should be stored here, rather than in global variables or |
| 10 | + * static member variables. |
| 11 | + * |
| 12 | + * A context object is passed to almost all SecurePoll constructors. This class |
| 13 | + * provides factory functions for these objects, to simplify object creation |
| 14 | + * and avoid having to use the SecurePoll_* prefixed class names. |
| 15 | + * |
| 16 | + * For debugging purposes, a var_dump() workalike which omits context objects |
| 17 | + * is available as $context->varDump(). |
| 18 | + */ |
| 19 | +class SecurePoll_Context { |
| 20 | + /** Language fallback sequence */ |
| 21 | + public $languages = array( 'en' ); |
| 22 | + |
| 23 | + /** Message text cache */ |
| 24 | + var $messageCache = array(); |
| 25 | + |
| 26 | + /** |
| 27 | + * Which messages are loaded. 2-d array: language and entity ID, value arbitrary. |
| 28 | + */ |
| 29 | + var $messagesLoaded = array(); |
| 30 | + |
| 31 | + /** ParserOptions instance used for message parsing */ |
| 32 | + var $parserOptions; |
| 33 | + |
| 34 | + /** The store class, for lazy loading */ |
| 35 | + var $storeClass = 'SecurePoll_DBStore'; |
| 36 | + |
| 37 | + /** The store object */ |
| 38 | + var $store; |
| 39 | + |
| 40 | + /** The SecurePoll_Random instance */ |
| 41 | + var $random; |
| 42 | + |
| 43 | + /** The Database instance */ |
| 44 | + var $db; |
| 45 | + |
| 46 | + /** |
| 47 | + * Create a new SecurePoll_Context with an XML file as the storage backend. |
| 48 | + * Returns false if there was a problem with the file, like a parse error. |
| 49 | + */ |
| 50 | + static function newFromXmlFile( $fileName ) { |
| 51 | + $context = new self; |
| 52 | + $store = new SecurePoll_XMLStore( $fileName ); |
| 53 | + $context->setStore( $store ); |
| 54 | + $success = $store->readFile(); |
| 55 | + if ( $success ) { |
| 56 | + return $context; |
| 57 | + } else { |
| 58 | + return false; |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + /** Get the ParserOptions instance */ |
| 63 | + function getParserOptions() { |
| 64 | + if ( !$this->parserOptions ) { |
| 65 | + $this->parserOptions = new ParserOptions; |
| 66 | + } |
| 67 | + return $this->parserOptions; |
| 68 | + } |
| 69 | + |
| 70 | + /** Get the SecurePoll_Store instance */ |
| 71 | + function getStore() { |
| 72 | + if ( !isset( $this->store ) ) { |
| 73 | + $this->store = new $this->storeClass; |
| 74 | + } |
| 75 | + return $this->store; |
| 76 | + } |
| 77 | + |
| 78 | + /** Get a Title object for Special:SecurePoll */ |
| 79 | + function getSpecialTitle( $subpage = false ) { |
| 80 | + return SpecialPage::getTitleFor( 'SecurePoll', $subpage ); |
| 81 | + } |
| 82 | + |
| 83 | + /** Set the store class */ |
| 84 | + function setStoreClass( $class ) { |
| 85 | + $this->store = null; |
| 86 | + $this->storeClass = $class; |
| 87 | + } |
| 88 | + |
| 89 | + /** Set the store object. Overrides any previous store class. */ |
| 90 | + function setStore( $store ) { |
| 91 | + $this->store = $store; |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Get an election object from the store, with a given entity ID. Returns |
| 96 | + * false if it does not exist. |
| 97 | + */ |
| 98 | + function getElection( $id ) { |
| 99 | + $info = $this->getStore()->getElectionInfo( array( $id ) ); |
| 100 | + if ( $info ) { |
| 101 | + return $this->newElection( reset( $info ) ); |
| 102 | + } else { |
| 103 | + return false; |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + /** |
| 108 | + * Get an election object from the store, with a given name. Returns false |
| 109 | + * if there is no such election. |
| 110 | + */ |
| 111 | + function getElectionByTitle( $name ) { |
| 112 | + $info = $this->getStore()->getElectionInfoByTitle( array( $name ) ); |
| 113 | + if ( $info ) { |
| 114 | + return $this->newElection( reset( $info ) ); |
| 115 | + } else { |
| 116 | + return false; |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + /** |
| 121 | + * Get an election object from a securepoll_elections DB row. This will fail |
| 122 | + * if the current store class does not support database operations. |
| 123 | + */ |
| 124 | + function newElectionFromRow( $row ) { |
| 125 | + $info = $this->getStore()->decodeElectionRow( $row ); |
| 126 | + return $this->newElection( $info ); |
| 127 | + } |
| 128 | + |
| 129 | + /** |
| 130 | + * Get a voter object from a securepoll_voters row |
| 131 | + */ |
| 132 | + function newVoterFromRow( $row ) { |
| 133 | + return SecurePoll_Voter::newFromRow( $this, $row ); |
| 134 | + } |
| 135 | + |
| 136 | + /** |
| 137 | + * Create a voter with the given parameters. Assumes the voter does not exist, |
| 138 | + * and inserts it into the database. |
| 139 | + * |
| 140 | + * The row needs to be locked before this function is called, to avoid |
| 141 | + * duplicate key errors. |
| 142 | + */ |
| 143 | + function createVoter( $params ) { |
| 144 | + return SecurePoll_Voter::createVoter( $this, $params ); |
| 145 | + } |
| 146 | + |
| 147 | + /** |
| 148 | + * Create a voter object from the database |
| 149 | + * @return SecurePoll_Voter or false if the ID is not valid |
| 150 | + */ |
| 151 | + function getVoter( $id ) { |
| 152 | + return SecurePoll_Voter::newFromId( $this, $id ); |
| 153 | + } |
| 154 | + |
| 155 | + /** |
| 156 | + * Get a SecurePoll_Random instance. This provides cryptographic random |
| 157 | + * number generation. |
| 158 | + */ |
| 159 | + function getRandom() { |
| 160 | + if ( !$this->random ) { |
| 161 | + $this->random = new SecurePoll_Random; |
| 162 | + } |
| 163 | + return $this->random; |
| 164 | + } |
| 165 | + /** |
| 166 | + * Set the global language fallback sequence. |
| 167 | + * |
| 168 | + * @param $languages array A list of language codes. When a message is |
| 169 | + * requested, the first code in the array will be tried first, followed |
| 170 | + * by the subsequent codes. |
| 171 | + */ |
| 172 | + function setLanguages( $languages ) { |
| 173 | + $this->languages = $languages; |
| 174 | + } |
| 175 | + |
| 176 | + /** |
| 177 | + * Get some messages from the backend store or the cache. |
| 178 | + * This is an internal interface for SecurePoll_Entity, generally you |
| 179 | + * should use SecurePoll_Entity::getMessage() instead. |
| 180 | + * |
| 181 | + * @param $lang Language code |
| 182 | + * @param $ids Entity IDs |
| 183 | + */ |
| 184 | + function getMessages( $lang, $ids ) { |
| 185 | + if ( isset( $this->messagesLoaded[$lang] ) ) { |
| 186 | + $cacheRow = $this->messagesLoaded[$lang]; |
| 187 | + $uncachedIds = array_flip( $ids ); |
| 188 | + foreach ( $uncachedIds as $id => $unused ) { |
| 189 | + if ( isset( $cacheRow[$id] ) ) { |
| 190 | + unset( $uncachedIds[$id] ); |
| 191 | + } |
| 192 | + } |
| 193 | + if ( count( $uncachedIds ) ) { |
| 194 | + $messages = $this->getStore()->getMessages( $lang, array_keys( $uncachedIds ) ); |
| 195 | + $this->messageCache[$lang] = $this->messageCache[$lang] + $messages; |
| 196 | + $this->messagesLoaded[$lang] = $this->messagesLoaded[$lang] + $uncachedIds; |
| 197 | + } |
| 198 | + return array_intersect_key( $this->messageCache[$lang], array_flip( $ids ) ); |
| 199 | + } else { |
| 200 | + $this->messagesLoaded[$lang] = $ids; |
| 201 | + $this->messageCache[$lang] = $this->getStore()->getMessages( $lang, $ids ); |
| 202 | + return $this->messageCache[$lang]; |
| 203 | + } |
| 204 | + } |
| 205 | + |
| 206 | + /** |
| 207 | + * Get a particular message. |
| 208 | + * This is an internal interface for SecurePoll_Entity, generally you |
| 209 | + * should use SecurePoll_Entity::getMessage() instead. |
| 210 | + * |
| 211 | + * @param $lang Language code |
| 212 | + * @param $id Entity ID |
| 213 | + * @param $key Message key |
| 214 | + */ |
| 215 | + function getMessage( $lang, $id, $key ) { |
| 216 | + if ( !isset( $this->messagesLoaded[$lang][$id] ) ) { |
| 217 | + $this->getMessages( $lang, array( $id ) ); |
| 218 | + } |
| 219 | + if ( isset( $this->messageCache[$lang][$id][$key] ) ) { |
| 220 | + return $this->messageCache[$lang][$id][$key]; |
| 221 | + } else { |
| 222 | + return false; |
| 223 | + } |
| 224 | + } |
| 225 | + |
| 226 | + /** |
| 227 | + * Get a database object, or throw an exception if the current store object |
| 228 | + * does not support database operations. |
| 229 | + */ |
| 230 | + function getDB() { |
| 231 | + if ( !isset( $this->db ) ) { |
| 232 | + $this->db = $this->getStore()->getDB(); |
| 233 | + } |
| 234 | + return $this->db; |
| 235 | + } |
| 236 | + |
| 237 | + function newElection( $info ) { |
| 238 | + return new SecurePoll_Election( $this, $info ); |
| 239 | + } |
| 240 | + |
| 241 | + function newQuestion( $info ) { |
| 242 | + return new SecurePoll_Question( $this, $info ); |
| 243 | + } |
| 244 | + |
| 245 | + function newOption( $info ) { |
| 246 | + return new SecurePoll_Option( $this, $info ); |
| 247 | + } |
| 248 | + |
| 249 | + function newCrypt( $type, $election ) { |
| 250 | + return SecurePoll_Crypt::factory( $this, $type, $election ); |
| 251 | + } |
| 252 | + |
| 253 | + function newTallier( $type, $question ) { |
| 254 | + return SecurePoll_Tallier::factory( $this, $type, $question ); |
| 255 | + } |
| 256 | + |
| 257 | + function newBallot( $type, $election ) { |
| 258 | + return SecurePoll_Ballot::factory( $this, $type, $election ); |
| 259 | + } |
| 260 | + |
| 261 | + function newAuth( $type ) { |
| 262 | + return SecurePoll_Auth::factory( $this, $type ); |
| 263 | + } |
| 264 | + |
| 265 | + function newVoter( $params ) { |
| 266 | + return new SecurePoll_Voter( $this, $params ); |
| 267 | + } |
| 268 | + |
| 269 | + function newElectionTallier( $election ) { |
| 270 | + return new SecurePoll_ElectionTallier( $this, $election ); |
| 271 | + } |
| 272 | + |
| 273 | + /** |
| 274 | + * Debugging function to output a representation of a mixed-type variable, |
| 275 | + * but omitting the $obj->context member variables for brevity. |
| 276 | + * |
| 277 | + * @param $var mixed |
| 278 | + * @param $return True to return the text instead of echoing |
| 279 | + * @param $level Recursion level, leave this as zero when calling. |
| 280 | + */ |
| 281 | + function varDump( $var, $return = false, $level = 0 ) { |
| 282 | + $tab = ' '; |
| 283 | + $indent = str_repeat( $tab, $level ); |
| 284 | + if ( is_array( $var ) ) { |
| 285 | + $s = "array(\n"; |
| 286 | + foreach ( $var as $key => $value ) { |
| 287 | + $s .= "$indent$tab" . $this->varDump( $key, true, $level + 1 ) . " => " . |
| 288 | + $this->varDump( $value, true, $level + 1 ) . ",\n"; |
| 289 | + } |
| 290 | + $s .= "{$indent})"; |
| 291 | + } elseif ( is_object( $var ) ) { |
| 292 | + $props = (array)$var; |
| 293 | + $s = get_class( $var ) . " {\n"; |
| 294 | + foreach ( $props as $key => $value ) { |
| 295 | + $s .= "$indent$tab" . $this->varDump( $key, true, $level + 1 ) . " => "; |
| 296 | + if ( $key === 'context' ) { |
| 297 | + $s .= "[CONTEXT],\n"; |
| 298 | + } else { |
| 299 | + $s .= $this->varDump( $value, true, $level + 1 ) . ",\n"; |
| 300 | + } |
| 301 | + } |
| 302 | + $s .= "{$indent}}"; |
| 303 | + } else { |
| 304 | + $s = var_export( $var, true ); |
| 305 | + } |
| 306 | + if ( $level == 0 ) { |
| 307 | + $s .= "\n"; |
| 308 | + } |
| 309 | + if ( $return ) { |
| 310 | + return $s; |
| 311 | + } else { |
| 312 | + echo $s; |
| 313 | + } |
| 314 | + } |
| 315 | +} |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/includes/Context.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 316 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/TranslatePage.php |
— | — | @@ -17,7 +17,7 @@ |
18 | 18 | } |
19 | 19 | |
20 | 20 | $electionId = intval( $params[0] ); |
21 | | - $this->election = $this->parent->getElection( $electionId ); |
| 21 | + $this->election = $this->context->getElection( $electionId ); |
22 | 22 | if ( !$this->election ) { |
23 | 23 | $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId ); |
24 | 24 | return; |
— | — | @@ -53,6 +53,11 @@ |
54 | 54 | return; |
55 | 55 | } |
56 | 56 | |
| 57 | + # Set a subtitle to return to the language selector |
| 58 | + $this->parent->setSubtitle( array( |
| 59 | + $this->getTitle(), |
| 60 | + wfMsg( 'securepoll-translate-title', $this->election->getMessage( 'title' ) ) ) ); |
| 61 | + |
57 | 62 | # If the request was posted, do the submit |
58 | 63 | if ( $wgRequest->wasPosted() && $wgRequest->getVal( 'action' ) == 'submit' ) { |
59 | 64 | $this->doSubmit( $secondary ); |
— | — | @@ -102,7 +107,7 @@ |
103 | 108 | /** |
104 | 109 | * @return Title |
105 | 110 | */ |
106 | | - function getTitle( $lang ) { |
| 111 | + function getTitle( $lang = false ) { |
107 | 112 | $subpage = 'translate/' . $this->election->getId(); |
108 | 113 | if ( $lang !== false ) { |
109 | 114 | $subpage .= '/' . $lang; |
— | — | @@ -166,7 +171,7 @@ |
167 | 172 | } |
168 | 173 | } |
169 | 174 | if ( $replaceBatch ) { |
170 | | - $dbw = wfGetDB( DB_MASTER ); |
| 175 | + $dbw = $this->context->getDB(); |
171 | 176 | $dbw->replace( |
172 | 177 | 'securepoll_msgs', |
173 | 178 | array( array( 'msg_entity', 'msg_lang', 'msg_key' ) ), |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Store.php |
— | — | @@ -0,0 +1,590 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * This is an abstraction of the persistence layer, to allow XML dumps to be |
| 6 | + * operated on and tallied, like elections in the local DB. |
| 7 | + * |
| 8 | + * Most of the UI layer has no need for this abstraction, and so we provide |
| 9 | + * direct database access via getDB() to ease development of those components. |
| 10 | + * The XML store will throw an exception if getDB() is called on it. |
| 11 | + * |
| 12 | + * Most of the functions here are internal interfaces for the use of |
| 13 | + * the entity classes (election, question and option). The entity classes |
| 14 | + * and SecurePoll_Context provide methods that are more appropriate for general |
| 15 | + * users. |
| 16 | + */ |
| 17 | +interface SecurePoll_Store { |
| 18 | + /** |
| 19 | + * Get an array of messages with a given language, and entity IDs |
| 20 | + * in a given array of IDs. The return format is a 2-d array mapping ID |
| 21 | + * and message key to value. |
| 22 | + */ |
| 23 | + function getMessages( $lang, $ids ); |
| 24 | + |
| 25 | + /** |
| 26 | + * Get a list of languages that the given entity IDs have messages for. |
| 27 | + * Returns an array of language codes. |
| 28 | + */ |
| 29 | + function getLangList( $ids ); |
| 30 | + |
| 31 | + /** |
| 32 | + * Get an array of properties for a given set of IDs. Returns a 2-d array |
| 33 | + * mapping IDs and property keys to values. |
| 34 | + */ |
| 35 | + function getProperties( $ids ); |
| 36 | + |
| 37 | + /** |
| 38 | + * Get information about a set of elections, specifically the data that |
| 39 | + * is stored in the securepoll_elections row in the DB. Returns a 2-d |
| 40 | + * array mapping ID to associative array of properties. |
| 41 | + */ |
| 42 | + function getElectionInfo( $ids ); |
| 43 | + |
| 44 | + /** |
| 45 | + * Get election information for a given set of names. |
| 46 | + */ |
| 47 | + function getElectionInfoByTitle( $names ); |
| 48 | + |
| 49 | + /** |
| 50 | + * Convert a row from the securepoll_elections table into an associative |
| 51 | + * array suitable for return by getElectionInfo(). |
| 52 | + */ |
| 53 | + function decodeElectionRow( $row ); |
| 54 | + |
| 55 | + /** |
| 56 | + * Get a database connection object. |
| 57 | + */ |
| 58 | + function getDB(); |
| 59 | + |
| 60 | + /** |
| 61 | + * Get an associative array of information about all questions in a given |
| 62 | + * election. |
| 63 | + */ |
| 64 | + function getQuestionInfo( $electionId ); |
| 65 | + |
| 66 | + /** |
| 67 | + * Call a callback function for all valid votes with a given election ID. |
| 68 | + */ |
| 69 | + function callbackValidVotes( $electionId, $callback ); |
| 70 | +} |
| 71 | + |
| 72 | +/** |
| 73 | + * Storage class for a DB backend. This is the one that's most often used. |
| 74 | + */ |
| 75 | +class SecurePoll_DBStore implements SecurePoll_Store { |
| 76 | + function getMessages( $lang, $ids ) { |
| 77 | + $db = $this->getDB(); |
| 78 | + $res = $db->select( |
| 79 | + 'securepoll_msgs', |
| 80 | + '*', |
| 81 | + array( |
| 82 | + 'msg_entity' => $ids, |
| 83 | + 'msg_lang' => $lang |
| 84 | + ), |
| 85 | + __METHOD__ |
| 86 | + ); |
| 87 | + $messages = array(); |
| 88 | + foreach ( $res as $row ) { |
| 89 | + $messages[$row->msg_entity][$row->msg_key] = $row->msg_text; |
| 90 | + } |
| 91 | + return $messages; |
| 92 | + } |
| 93 | + |
| 94 | + function getLangList( $ids ) { |
| 95 | + $db = $this->getDB(); |
| 96 | + $res = $db->select( |
| 97 | + 'securepoll_msgs', |
| 98 | + 'DISTINCT msg_lang', |
| 99 | + array( |
| 100 | + 'msg_entity' => $ids |
| 101 | + ), |
| 102 | + __METHOD__ ); |
| 103 | + $langs = array(); |
| 104 | + foreach ( $res as $row ) { |
| 105 | + $langs[] = $row->msg_lang; |
| 106 | + } |
| 107 | + return $langs; |
| 108 | + } |
| 109 | + |
| 110 | + function getProperties( $ids ) { |
| 111 | + $db = $this->getDB(); |
| 112 | + $res = $db->select( |
| 113 | + 'securepoll_properties', |
| 114 | + '*', |
| 115 | + array( 'pr_entity' => $ids ), |
| 116 | + __METHOD__ ); |
| 117 | + $properties = array(); |
| 118 | + foreach ( $res as $row ) { |
| 119 | + $properties[$row->pr_entity][$row->pr_key] = $row->pr_value; |
| 120 | + } |
| 121 | + return $properties; |
| 122 | + } |
| 123 | + |
| 124 | + function getElectionInfo( $ids ) { |
| 125 | + $ids = (array)$ids; |
| 126 | + $db = $this->getDB(); |
| 127 | + $res = $db->select( |
| 128 | + 'securepoll_elections', |
| 129 | + '*', |
| 130 | + array( 'el_entity' => $ids ), |
| 131 | + __METHOD__ ); |
| 132 | + $infos = array(); |
| 133 | + foreach ( $res as $row ) { |
| 134 | + $infos[$row->el_entity] = $this->decodeElectionRow( $row ); |
| 135 | + } |
| 136 | + return $infos; |
| 137 | + } |
| 138 | + |
| 139 | + function getElectionInfoByTitle( $names ) { |
| 140 | + $names = (array)$names; |
| 141 | + $db = $this->getDB(); |
| 142 | + $res = $db->select( |
| 143 | + 'securepoll_elections', |
| 144 | + '*', |
| 145 | + array( 'el_title' => $names ), |
| 146 | + __METHOD__ ); |
| 147 | + $infos = array(); |
| 148 | + foreach ( $res as $row ) { |
| 149 | + $infos[$row->el_title] = $this->decodeElectionRow( $row ); |
| 150 | + } |
| 151 | + return $infos; |
| 152 | + } |
| 153 | + |
| 154 | + function decodeElectionRow( $row ) { |
| 155 | + static $map = array( |
| 156 | + 'id' => 'el_entity', |
| 157 | + 'title' => 'el_title', |
| 158 | + 'ballot' => 'el_ballot', |
| 159 | + 'tally' => 'el_tally', |
| 160 | + 'primaryLang' => 'el_primary_lang', |
| 161 | + 'startDate' => 'el_start_date', |
| 162 | + 'endDate' => 'el_end_date', |
| 163 | + 'auth' => 'el_auth_type' |
| 164 | + ); |
| 165 | + |
| 166 | + $info = array(); |
| 167 | + foreach ( $map as $key => $field ) { |
| 168 | + if ( $key == 'startDate' || $key == 'endDate' ) { |
| 169 | + $info[$key] = wfTimestamp( TS_MW, $row->$field ); |
| 170 | + } else { |
| 171 | + $info[$key] = $row->$field; |
| 172 | + } |
| 173 | + } |
| 174 | + return $info; |
| 175 | + } |
| 176 | + |
| 177 | + function getDB() { |
| 178 | + return wfGetDB( DB_MASTER ); |
| 179 | + } |
| 180 | + |
| 181 | + function getQuestionInfo( $electionId ) { |
| 182 | + $db = $this->getDB(); |
| 183 | + $res = $db->select( |
| 184 | + array( 'securepoll_questions', 'securepoll_options' ), |
| 185 | + '*', |
| 186 | + array( |
| 187 | + 'qu_election' => $electionId, |
| 188 | + 'op_question=qu_entity' |
| 189 | + ), |
| 190 | + __METHOD__, |
| 191 | + array( 'ORDER BY' => 'qu_index, qu_entity' ) |
| 192 | + ); |
| 193 | + |
| 194 | + $questions = array(); |
| 195 | + $options = array(); |
| 196 | + $questionId = false; |
| 197 | + foreach ( $res as $row ) { |
| 198 | + if ( $questionId === false ) { |
| 199 | + } elseif ( $questionId !== $row->qu_entity ) { |
| 200 | + $questions[] = array( 'id' => $questionId, 'options' => $options ); |
| 201 | + $options = array(); |
| 202 | + } |
| 203 | + $options[] = array( 'id' => $row->op_entity ); |
| 204 | + $questionId = $row->qu_entity; |
| 205 | + } |
| 206 | + if ( $questionId !== false ) { |
| 207 | + $questions[] = array( 'id' => $questionId, 'options' => $options ); |
| 208 | + } |
| 209 | + return $questions; |
| 210 | + } |
| 211 | + |
| 212 | + function callbackValidVotes( $electionId, $callback ) { |
| 213 | + $dbr = $this->getDB(); |
| 214 | + $res = $dbr->select( |
| 215 | + 'securepoll_votes', |
| 216 | + array( 'vote_record' ), |
| 217 | + array( |
| 218 | + 'vote_election' => $electionId, |
| 219 | + 'vote_current' => 1, |
| 220 | + 'vote_struck' => 0 |
| 221 | + ), __METHOD__ |
| 222 | + ); |
| 223 | + foreach ( $res as $row ) { |
| 224 | + $status = call_user_func( $callback, $this, $row->vote_record ); |
| 225 | + if ( $status && !$status->isOK() ) { |
| 226 | + return $status; |
| 227 | + } |
| 228 | + } |
| 229 | + return Status::newGood(); |
| 230 | + } |
| 231 | +} |
| 232 | + |
| 233 | +/** |
| 234 | + * Storage class that stores all data in local memory. The memory must be |
| 235 | + * initialised somehow, methods for this are not provided except in the |
| 236 | + * subclass. |
| 237 | + */ |
| 238 | +class SecurePoll_MemoryStore implements SecurePoll_Store { |
| 239 | + var $messages, $properties, $idsByName, $votes; |
| 240 | + var $entityInfo; |
| 241 | + |
| 242 | + /** |
| 243 | + * Get an array containing all election IDs stored in this object |
| 244 | + */ |
| 245 | + function getAllElectionIds() { |
| 246 | + $electionIds = array(); |
| 247 | + foreach ( $this->entityInfo as $info ) { |
| 248 | + if ( $info['type'] !== 'election' ) { |
| 249 | + continue; |
| 250 | + } |
| 251 | + $electionIds[] = $info['id']; |
| 252 | + } |
| 253 | + return $electionIds; |
| 254 | + } |
| 255 | + |
| 256 | + function getMessages( $lang, $ids ) { |
| 257 | + if ( !isset( $this->messages[$lang] ) ) { |
| 258 | + return array(); |
| 259 | + } |
| 260 | + return array_intersect_key( $this->messages[$lang], array_flip( $ids ) ); |
| 261 | + } |
| 262 | + |
| 263 | + function getLangList( $ids ) { |
| 264 | + $langs = array(); |
| 265 | + foreach ( $this->messages as $lang => $langMessages ) { |
| 266 | + foreach ( $ids as $id ) { |
| 267 | + if ( isset( $langMessages[$id] ) ) { |
| 268 | + $langs[] = $lang; |
| 269 | + break; |
| 270 | + } |
| 271 | + } |
| 272 | + } |
| 273 | + return $langs; |
| 274 | + } |
| 275 | + |
| 276 | + function getProperties( $ids ) { |
| 277 | + $ids = (array)$ids; |
| 278 | + return array_intersect_key( $this->properties, array_flip( $ids ) ); |
| 279 | + } |
| 280 | + |
| 281 | + function getElectionInfo( $ids ) { |
| 282 | + $ids = (array)$ids; |
| 283 | + return array_intersect_key( $this->entityInfo, array_flip( $ids ) ); |
| 284 | + } |
| 285 | + |
| 286 | + function getElectionInfoByTitle( $names ) { |
| 287 | + $names = (array)$names; |
| 288 | + $ids = array_intersect_key( $this->idsByName, array_flip( $names ) ); |
| 289 | + $info = array_intersect_key( $this->entityInfo, array_flip( $ids ) ); |
| 290 | + return $info; |
| 291 | + } |
| 292 | + |
| 293 | + function getQuestionInfo( $electionId ) { |
| 294 | + return $this->entityInfo[$electionId]['questions']; |
| 295 | + } |
| 296 | + |
| 297 | + function decodeElectionRow( $row ) { |
| 298 | + throw new MWException( 'Internal error: attempt to use decodeElectionRow() with ' . |
| 299 | + 'a storage class that doesn\'t support it.' ); |
| 300 | + } |
| 301 | + |
| 302 | + function getDB() { |
| 303 | + throw new MWException( 'Internal error: attempt to use getDB() when the database ' . |
| 304 | + 'is disabled.' ); |
| 305 | + } |
| 306 | + |
| 307 | + function callbackValidVotes( $electionId, $callback ) { |
| 308 | + if ( !isset( $this->votes[$electionId] ) ) { |
| 309 | + return Status::newGood(); |
| 310 | + } |
| 311 | + foreach ( $this->votes[$electionId] as $vote ) { |
| 312 | + $status = call_user_func( $callback, $this, $vote ); |
| 313 | + if ( !$status->isOK() ) { |
| 314 | + return $status; |
| 315 | + } |
| 316 | + } |
| 317 | + return Status::newGood(); |
| 318 | + } |
| 319 | +} |
| 320 | + |
| 321 | +/** |
| 322 | + * Storage class for an XML file store. Election configuration data is cached, |
| 323 | + * and vote data can be loaded into a tallier on demand. |
| 324 | + */ |
| 325 | +class SecurePoll_XMLStore extends SecurePoll_MemoryStore { |
| 326 | + var $xmlReader, $fileName; |
| 327 | + var $voteCallback, $voteElectionId; |
| 328 | + |
| 329 | + /** Valid entity info keys by entity type. */ |
| 330 | + static $entityInfoKeys = array( |
| 331 | + 'election' => array( |
| 332 | + 'id', |
| 333 | + 'title', |
| 334 | + 'ballot', |
| 335 | + 'tally', |
| 336 | + 'primaryLang', |
| 337 | + 'startDate', |
| 338 | + 'endDate', |
| 339 | + 'auth' |
| 340 | + ), |
| 341 | + 'question' => array( 'id' ), |
| 342 | + 'option' => array( 'id' ), |
| 343 | + ); |
| 344 | + |
| 345 | + /** The type of each entity child and its corresponding (plural) info element */ |
| 346 | + static $childTypes = array( |
| 347 | + 'election' => array( 'question' => 'questions' ), |
| 348 | + 'question' => array( 'option' => 'options' ), |
| 349 | + 'option' => array() |
| 350 | + ); |
| 351 | + |
| 352 | + /** All entity types */ |
| 353 | + static $entityTypes = array( 'election', 'question', 'option' ); |
| 354 | + |
| 355 | + /** |
| 356 | + * Constructor. Note that readFile() must be called before any information |
| 357 | + * can be accessed. SecurePoll_Context::newFromXmlFile() is a shortcut |
| 358 | + * method for this. |
| 359 | + */ |
| 360 | + function __construct( $fileName ) { |
| 361 | + $this->fileName = $fileName; |
| 362 | + } |
| 363 | + |
| 364 | + /** |
| 365 | + * Read the file and return boolean success. |
| 366 | + */ |
| 367 | + function readFile() { |
| 368 | + $this->xmlReader = new XMLReader; |
| 369 | + $xr = $this->xmlReader; |
| 370 | + $fileName = realpath( $this->fileName ); |
| 371 | + $uri = 'file://' . str_replace( '%2F', '/', rawurlencode( $fileName ) ); |
| 372 | + $xr->open( $uri ); |
| 373 | + $xr->setParserProperty( XMLReader::SUBST_ENTITIES, true ); |
| 374 | + $success = $this->doTopLevel(); |
| 375 | + $xr->close(); |
| 376 | + $this->xmlReader = null; |
| 377 | + return $success; |
| 378 | + } |
| 379 | + |
| 380 | + /** |
| 381 | + * Do the top-level document element, and return success. |
| 382 | + */ |
| 383 | + function doTopLevel() { |
| 384 | + $xr = $this->xmlReader; |
| 385 | + |
| 386 | + # Check document element |
| 387 | + while ( $xr->read() && $xr->nodeType !== XMLReader::ELEMENT ); |
| 388 | + if ( $xr->name != 'SecurePoll' ) { |
| 389 | + wfDebug( __METHOD__.": invalid document element\n" ); |
| 390 | + return false; |
| 391 | + } |
| 392 | + |
| 393 | + while ( $xr->read() ) { |
| 394 | + if ( $xr->nodeType !== XMLReader::ELEMENT ) { |
| 395 | + continue; |
| 396 | + } |
| 397 | + if ( $xr->name !== 'election' ) { |
| 398 | + continue; |
| 399 | + } |
| 400 | + if ( !$this->doElection() ) { |
| 401 | + return false; |
| 402 | + } |
| 403 | + } |
| 404 | + return true; |
| 405 | + } |
| 406 | + |
| 407 | + /** |
| 408 | + * Read an <election> element and position the cursor past the end of it. |
| 409 | + * Return success. |
| 410 | + */ |
| 411 | + function doElection() { |
| 412 | + $xr = $this->xmlReader; |
| 413 | + if ( $xr->isEmptyElement ) { |
| 414 | + wfDebug( __METHOD__.": unexpected empty element\n" ); |
| 415 | + return false; |
| 416 | + } |
| 417 | + $xr->read(); |
| 418 | + $electionInfo = false; |
| 419 | + while ( $xr->nodeType !== XMLReader::NONE ) { |
| 420 | + if ( $xr->nodeType === XMLReader::END_ELEMENT ) { |
| 421 | + # Finished |
| 422 | + return true; |
| 423 | + } |
| 424 | + if ( $xr->nodeType !== XMLReader::ELEMENT ) { |
| 425 | + # Skip comments, intervening text, etc. |
| 426 | + $xr->read(); |
| 427 | + continue; |
| 428 | + } |
| 429 | + if ( $xr->name === 'configuration' ) { |
| 430 | + # Load configuration |
| 431 | + $electionInfo = $this->readEntity( 'election' ); |
| 432 | + if ( $electionInfo === false ) { |
| 433 | + return false; |
| 434 | + } |
| 435 | + continue; |
| 436 | + } |
| 437 | + |
| 438 | + if ( $xr->name === 'vote' ) { |
| 439 | + # Notify tallier of vote record if requested |
| 440 | + if ( $this->voteCallback && $electionInfo |
| 441 | + && $electionInfo['id'] == $this->voteElectionId ) |
| 442 | + { |
| 443 | + $record = $this->readStringElement(); |
| 444 | + call_user_func( $this->voteCallback, $this, $record ); |
| 445 | + } else { |
| 446 | + $xr->next(); |
| 447 | + } |
| 448 | + continue; |
| 449 | + } |
| 450 | + |
| 451 | + wfDebug( __METHOD__.": ignoring unrecognised element <{$xr->name}>\n" ); |
| 452 | + $xr->next(); |
| 453 | + } |
| 454 | + wfDebug( __METHOD__.": unexpected end of stream\n" ); |
| 455 | + return false; |
| 456 | + } |
| 457 | + |
| 458 | + /** |
| 459 | + * Read an entity configuration element: <configuration>, <question> or |
| 460 | + * <option>, and position the cursor past the end of it. |
| 461 | + * |
| 462 | + * This function operates recursively to read child elements. It returns |
| 463 | + * the info array for the entity. |
| 464 | + */ |
| 465 | + function readEntity( $entityType ) { |
| 466 | + $xr = $this->xmlReader; |
| 467 | + $info = array( 'type' => $entityType ); |
| 468 | + $messages = array(); |
| 469 | + $properties = array(); |
| 470 | + $children = array(); |
| 471 | + if ( $xr->isEmptyElement ) { |
| 472 | + wfDebug( __METHOD__.": unexpected empty element\n" ); |
| 473 | + $xr->read(); |
| 474 | + return false; |
| 475 | + } |
| 476 | + $xr->read(); |
| 477 | + |
| 478 | + while ( true ) { |
| 479 | + if ( $xr->nodeType === XMLReader::NONE ) { |
| 480 | + wfDebug( __METHOD__.": unexpected end of stream\n" ); |
| 481 | + return false; |
| 482 | + } |
| 483 | + if ( $xr->nodeType === XMLReader::END_ELEMENT ) { |
| 484 | + # End of entity |
| 485 | + $xr->read(); |
| 486 | + break; |
| 487 | + } |
| 488 | + if ( $xr->nodeType !== XMLReader::ELEMENT ) { |
| 489 | + # Intervening text, comments, etc. |
| 490 | + $xr->read(); |
| 491 | + continue; |
| 492 | + } |
| 493 | + if ( $xr->name === 'message' ) { |
| 494 | + $name = $xr->getAttribute( 'name' ); |
| 495 | + $lang = $xr->getAttribute( 'lang' ); |
| 496 | + $value = $this->readStringElement(); |
| 497 | + $messages[$lang][$name] = $value; |
| 498 | + continue; |
| 499 | + } |
| 500 | + if ( $xr->name == 'property' ) { |
| 501 | + $name = $xr->getAttribute( 'name' ); |
| 502 | + $value = $this->readStringElement(); |
| 503 | + $properties[$name] = $value; |
| 504 | + continue; |
| 505 | + } |
| 506 | + |
| 507 | + # Info elements |
| 508 | + if ( in_array( $xr->name, self::$entityInfoKeys[$entityType] ) ) { |
| 509 | + $name = $xr->name; |
| 510 | + $value = $this->readStringElement(); |
| 511 | + # Fix date format |
| 512 | + if ( $name == 'startDate' || $name == 'endDate' ) { |
| 513 | + $value = wfTimestamp( TS_MW, $value ); |
| 514 | + } |
| 515 | + $info[$name] = $value; |
| 516 | + continue; |
| 517 | + } |
| 518 | + |
| 519 | + # Child elements |
| 520 | + if ( isset( self::$childTypes[$entityType][$xr->name] ) ) { |
| 521 | + $infoKey = self::$childTypes[$entityType][$xr->name]; |
| 522 | + $childInfo = $this->readEntity( $xr->name ); |
| 523 | + if ( !$childInfo ) { |
| 524 | + return false; |
| 525 | + } |
| 526 | + $info[$infoKey][] = $childInfo; |
| 527 | + continue; |
| 528 | + } |
| 529 | + |
| 530 | + wfDebug( __METHOD__.": ignoring unrecognised element <{$xr->name}>\n" ); |
| 531 | + $xr->next(); |
| 532 | + } |
| 533 | + |
| 534 | + if ( !isset( $info['id'] ) ) { |
| 535 | + wfDebug( __METHOD__.": missing id element in <$entityType>\n" ); |
| 536 | + return false; |
| 537 | + } |
| 538 | + $id = $info['id']; |
| 539 | + if ( isset( $info['title'] ) ) { |
| 540 | + $this->idsByName[$info['title']] = $id; |
| 541 | + } |
| 542 | + $this->entityInfo[$id] = $info; |
| 543 | + foreach ( $messages as $lang => $values ) { |
| 544 | + $this->messages[$lang][$id] = $values; |
| 545 | + } |
| 546 | + $this->properties[$id] = $properties; |
| 547 | + return $info; |
| 548 | + } |
| 549 | + |
| 550 | + /** |
| 551 | + * When the cursor is positioned on an element node, this reads the entire |
| 552 | + * element and returns the contents as a string. On return, the cursor is |
| 553 | + * positioned past the end of the element. |
| 554 | + */ |
| 555 | + function readStringElement() { |
| 556 | + $xr = $this->xmlReader; |
| 557 | + if ( $xr->isEmptyElement ) { |
| 558 | + $xr->read(); |
| 559 | + return ''; |
| 560 | + } |
| 561 | + $s = ''; |
| 562 | + $level = 1; |
| 563 | + while ( $xr->read() && $level ) { |
| 564 | + if ( $xr->nodeType == XMLReader::TEXT ) { |
| 565 | + $s .= $xr->value; |
| 566 | + continue; |
| 567 | + } |
| 568 | + if ( $xr->nodeType == XMLReader::ELEMENT && !$xr->isEmptyElement ) { |
| 569 | + $level++; |
| 570 | + continue; |
| 571 | + } |
| 572 | + if ( $xr->nodeType == XMLReader::END_ELEMENT ) { |
| 573 | + $level--; |
| 574 | + continue; |
| 575 | + } |
| 576 | + } |
| 577 | + return $s; |
| 578 | + } |
| 579 | + |
| 580 | + function callbackValidVotes( $electionId, $callback ) { |
| 581 | + $this->voteCallback = $callback; |
| 582 | + $this->voteElectionId = $electionId; |
| 583 | + $success = $this->readFile(); |
| 584 | + $this->voteCallback = $this->voteElectionId = null; |
| 585 | + if ( $success ) { |
| 586 | + return Status::newGood(); |
| 587 | + } else { |
| 588 | + return Status::newFatal( 'securepoll-dump-file-corrupt' ); |
| 589 | + } |
| 590 | + } |
| 591 | +} |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/includes/Store.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 592 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Tallier.php |
— | — | @@ -1,23 +1,78 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | 4 | abstract class SecurePoll_Tallier { |
5 | | - var $election; |
| 5 | + var $context, $question, $optionsById; |
6 | 6 | |
7 | | - abstract function addRecord( $record ); |
8 | | - abstract function getResult(); |
| 7 | + abstract function addVote( $scores ); |
| 8 | + abstract function getHtmlResult(); |
| 9 | + abstract function getTextResult(); |
9 | 10 | |
10 | | - static function factory( $type, $election ) { |
| 11 | + abstract function finishTally(); |
| 12 | + |
| 13 | + static function factory( $context, $type, $question ) { |
11 | 14 | switch ( $type ) { |
12 | 15 | case 'plurality': |
13 | | - return new SecurePoll_PluralityTallier( $election ); |
| 16 | + return new SecurePoll_PluralityTallier( $context, $question ); |
| 17 | + case 'schulze': |
| 18 | + return new SecurePoll_SchulzeTallier( $context, $question ); |
14 | 19 | default: |
15 | 20 | throw new MWException( "Invalid tallier type: $type" ); |
16 | 21 | } |
17 | 22 | } |
18 | 23 | |
19 | | - function __construct( $election ) { |
20 | | - $this->election = $election; |
| 24 | + function __construct( $context, $question ) { |
| 25 | + $this->context = $context; |
| 26 | + $this->question = $question; |
| 27 | + foreach ( $this->question->getOptions() as $option ) { |
| 28 | + $this->optionsById[$option->getId()] = $option; |
| 29 | + } |
21 | 30 | } |
| 31 | + |
| 32 | + function convertRanksToHtml( $ranks ) { |
| 33 | + $s = "<table class=\"securepoll-results\">"; |
| 34 | + $ids = array_keys( $ranks ); |
| 35 | + foreach ( $ids as $i => $oid ) { |
| 36 | + $rank = $ranks[$oid]; |
| 37 | + $prevRank = isset( $ids[$i-1] ) ? $ranks[$ids[$i-1]] : false; |
| 38 | + $nextRank = isset( $ids[$i+1] ) ? $ranks[$ids[$i+1]] : false; |
| 39 | + if ( $rank === $prevRank || $rank === $nextRank ) { |
| 40 | + $rank .= '*'; |
| 41 | + } |
| 42 | + |
| 43 | + $option = $this->optionsById[$oid]; |
| 44 | + $s .= "<tr>" . |
| 45 | + Xml::element( 'td', array(), $rank ) . |
| 46 | + Xml::element( 'td', array(), $option->parseMessage( 'text' ) ) . |
| 47 | + "</tr>\n"; |
| 48 | + } |
| 49 | + $s .= "</table>"; |
| 50 | + return $s; |
| 51 | + } |
| 52 | + |
| 53 | + function convertRanksToText( $ranks ) { |
| 54 | + $s = ''; |
| 55 | + $ids = array_keys( $ranks ); |
| 56 | + $colWidth = 6; |
| 57 | + foreach ( $this->optionsById as $option ) { |
| 58 | + $colWidth = max( $colWidth, $option->getMessage( 'text' ) ); |
| 59 | + } |
| 60 | + |
| 61 | + foreach ( $ids as $i => $oid ) { |
| 62 | + $rank = $ranks[$oid]; |
| 63 | + $prevRank = isset( $ids[$i-1] ) ? $ranks[$ids[$i-1]] : false; |
| 64 | + $nextRank = isset( $ids[$i+1] ) ? $ranks[$ids[$i+1]] : false; |
| 65 | + if ( $rank === $prevRank || $rank === $nextRank ) { |
| 66 | + $rank .= '*'; |
| 67 | + } |
| 68 | + |
| 69 | + $option = $this->optionsById[$oid]; |
| 70 | + $s .= str_pad( $rank, 6 ) . ' | ' . |
| 71 | + $option->getMessage( 'text' ) . "\n"; |
| 72 | + } |
| 73 | + return $s; |
| 74 | + } |
| 75 | + |
| 76 | + |
22 | 77 | } |
23 | 78 | |
24 | 79 | /** |
— | — | @@ -26,63 +81,510 @@ |
27 | 82 | class SecurePoll_PluralityTallier extends SecurePoll_Tallier { |
28 | 83 | var $tally = array(); |
29 | 84 | |
30 | | - function __construct( $election ) { |
31 | | - parent::__construct( $election ); |
32 | | - $questions = $this->election->getQuestions(); |
33 | | - foreach ( $questions as $question ) { |
34 | | - foreach ( $question->getOptions() as $option ) { |
35 | | - $this->tally[$question->getId()][$option->getId()] = 0; |
| 85 | + function __construct( $context, $question ) { |
| 86 | + parent::__construct( $context, $question ); |
| 87 | + foreach ( $question->getOptions() as $option ) { |
| 88 | + $this->tally[$option->getId()] = 0; |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + function addVote( $scores ) { |
| 93 | + foreach ( $scores as $oid => $score ) { |
| 94 | + if ( !isset( $this->tally[$oid] ) ) { |
| 95 | + wfDebug( __METHOD__.": unknown OID $oid\n" ); |
| 96 | + return false; |
36 | 97 | } |
| 98 | + $this->tally[$oid] += $score; |
37 | 99 | } |
| 100 | + return true; |
38 | 101 | } |
39 | 102 | |
40 | | - function addRecord( $record ) { |
41 | | - $i = 0; |
42 | | - $ballot = $this->election->getBallot(); |
43 | | - $scores = $ballot->unpackRecord( $record ); |
44 | | - if ( $scores === false ) { |
45 | | - return false; |
| 103 | + function finishTally() { |
| 104 | + // Sort the scores |
| 105 | + arsort( $this->tally ); |
| 106 | + } |
| 107 | + |
| 108 | + function getHtmlResult() { |
| 109 | + // Show the results |
| 110 | + $s = "<table class=\"securepoll-results\">\n"; |
| 111 | + |
| 112 | + foreach ( $this->tally as $oid => $rank ) { |
| 113 | + $option = $this->optionsById[$oid]; |
| 114 | + $s .= '<tr><td>' . $option->getMessage( 'text' ) . "</td>\n" . |
| 115 | + '<td>' . $this->tally[$oid] . "</td>\n" . |
| 116 | + "</tr>\n"; |
46 | 117 | } |
47 | | - foreach ( $scores as $qid => $questionScores ) { |
48 | | - if ( !isset( $this->tally[$qid] ) ) { |
49 | | - wfDebug( __METHOD__.": unknown QID $qid\n" ); |
| 118 | + $s .= "</table>\n"; |
| 119 | + return $s; |
| 120 | + } |
| 121 | + |
| 122 | + function getTextResult() { |
| 123 | + // Calculate column width |
| 124 | + $width = 10; |
| 125 | + foreach ( $this->tally as $oid => $rank ) { |
| 126 | + $option = $this->optionsById[$oid]; |
| 127 | + $width = max( $width, strlen( $option->getMessage( 'text' ) ) ); |
| 128 | + } |
| 129 | + if ( $width > 57 ) { |
| 130 | + $width = 57; |
| 131 | + } |
| 132 | + |
| 133 | + // Show the results |
| 134 | + $qtext = $this->question->getMessage( 'text' ); |
| 135 | + $s = ''; |
| 136 | + if ( $qtext !== '' ) { |
| 137 | + $s .= wordwrap( $qtext ) . "\n"; |
| 138 | + } |
| 139 | + foreach ( $this->tally as $oid => $rank ) { |
| 140 | + $option = $this->optionsById[$oid]; |
| 141 | + $otext = $option->getMessage( 'text' ); |
| 142 | + if ( strlen( $otext ) > $width ) { |
| 143 | + $otext = substr( $otext, 0, $width - 3 ) . '...'; |
| 144 | + } else { |
| 145 | + $otext = str_pad( $otext, $width ); |
| 146 | + } |
| 147 | + $s .= $otext . ' | ' . |
| 148 | + $this->tally[$option->getId()] . "\n"; |
| 149 | + } |
| 150 | + return $s; |
| 151 | + } |
| 152 | + |
| 153 | + function getRanks() { |
| 154 | + $ranks = array(); |
| 155 | + $currentRank = 1; |
| 156 | + $oids = array_keys( $this->tally ); |
| 157 | + $scores = array_values( $this->tally ); |
| 158 | + foreach ( $oids as $i => $oid ) { |
| 159 | + if ( $i > 0 && $scores[$i-1] !== $scores[$i] ) { |
| 160 | + $currentRank = $i + 1; |
| 161 | + } |
| 162 | + $ranks[$oid] = $currentRank; |
| 163 | + } |
| 164 | + return $ranks; |
| 165 | + } |
| 166 | +} |
| 167 | + |
| 168 | +abstract class SecurePoll_PairwiseTallier extends SecurePoll_Tallier { |
| 169 | + var $optionIds = array(); |
| 170 | + var $victories = array(); |
| 171 | + var $abbrevs; |
| 172 | + var $rowLabels = array(); |
| 173 | + |
| 174 | + function __construct( $context, $question ) { |
| 175 | + parent::__construct( $context, $question ); |
| 176 | + $this->optionIds = array(); |
| 177 | + foreach ( $question->getOptions() as $option ) { |
| 178 | + $this->optionIds[] = $option->getId(); |
| 179 | + } |
| 180 | + |
| 181 | + $this->victories = array(); |
| 182 | + foreach ( $this->optionIds as $i ) { |
| 183 | + foreach ( $this->optionIds as $j ) { |
| 184 | + $this->victories[$i][$j] = 0; |
| 185 | + } |
| 186 | + } |
| 187 | + } |
| 188 | + |
| 189 | + function addVote( $ranks ) { |
| 190 | + foreach ( $this->optionIds as $oid1 ) { |
| 191 | + if ( !isset( $ranks[$oid1] ) ) { |
| 192 | + wfDebug( "Invalid vote record, missing option $oid1\n" ); |
50 | 193 | return false; |
51 | 194 | } |
52 | | - foreach ( $questionScores as $oid => $score ) { |
53 | | - if ( !isset( $this->tally[$qid][$oid] ) ) { |
54 | | - wfDebug( __METHOD__.": unknown OID $oid\n" ); |
55 | | - return false; |
| 195 | + foreach ( $this->optionIds as $oid2 ) { |
| 196 | + # Lower = better |
| 197 | + if ( $ranks[$oid1] < $ranks[$oid2] ) { |
| 198 | + $this->victories[$oid1][$oid2]++; |
56 | 199 | } |
57 | | - $this->tally[$qid][$oid] += $score; |
58 | 200 | } |
59 | 201 | } |
60 | 202 | return true; |
61 | 203 | } |
62 | 204 | |
63 | | - function getResult() { |
64 | | - global $wgOut; |
65 | | - $questions = $this->election->getQuestions(); |
66 | | - |
67 | | - // Sort the scores |
68 | | - foreach ( $this->tally as &$scores ) { |
69 | | - arsort( $scores ); |
| 205 | + function getOptionAbbreviations() { |
| 206 | + if ( is_null( $this->abbrevs ) ) { |
| 207 | + $abbrevs = array(); |
| 208 | + foreach ( $this->question->getOptions() as $option ) { |
| 209 | + $text = $option->getMessage( 'text' ); |
| 210 | + $parts = explode( ' ', $text ); |
| 211 | + $initials = ''; |
| 212 | + foreach ( $parts as $part ) { |
| 213 | + if ( $part === '' || ctype_punct( $part[0] ) ) { |
| 214 | + continue; |
| 215 | + } |
| 216 | + $initials .= $part[0]; |
| 217 | + } |
| 218 | + if ( isset( $abbrevs[$initials] ) ) { |
| 219 | + $index = 2; |
| 220 | + while ( isset( $abbrevs[$initials . $index] ) ) { |
| 221 | + $index++; |
| 222 | + } |
| 223 | + $initials .= $index; |
| 224 | + } |
| 225 | + $abbrevs[$initials] = $option->getId(); |
| 226 | + } |
| 227 | + $this->abbrevs = array_flip( $abbrevs ); |
70 | 228 | } |
| 229 | + return $this->abbrevs; |
| 230 | + } |
71 | 231 | |
72 | | - // Show the results |
73 | | - $s = ''; |
74 | | - foreach ( $questions as $question ) { |
75 | | - if ( $s !== '' ) { |
76 | | - $s .= "<hr/>\n"; |
| 232 | + function getRowLabels( $format = 'html' ) { |
| 233 | + if ( !isset( $this->rowLabels[$format] ) ) { |
| 234 | + $rowLabels = array(); |
| 235 | + $abbrevs = $this->getOptionAbbreviations(); |
| 236 | + foreach ( $this->question->getOptions() as $option ) { |
| 237 | + if ( $format == 'html' ) { |
| 238 | + $label = $option->parseMessage( 'text' ); |
| 239 | + } else { |
| 240 | + $label = $option->getMessage( 'text' ); |
| 241 | + } |
| 242 | + if ( $label !== $abbrevs[$option->getId()] ) { |
| 243 | + $label .= ' (' . $abbrevs[$option->getId()] . ')'; |
| 244 | + } |
| 245 | + $rowLabels[$option->getId()] = $label; |
77 | 246 | } |
78 | | - $s .= $wgOut->parse( $question->getMessage( 'text' ) ) . |
79 | | - '<table class="securepoll-result-table" border="1">'; |
80 | | - foreach ( $question->getOptions() as $option ) { |
81 | | - $s .= '<tr><td>' . $option->getMessage( 'text' ) . "</td>\n" . |
82 | | - '<td>' . $this->tally[$question->getId()][$option->getId()] . "</td>\n" . |
83 | | - "</tr>\n"; |
| 247 | + $this->rowLabels[$format] = $rowLabels; |
| 248 | + } |
| 249 | + return $this->rowLabels[$format]; |
| 250 | + } |
| 251 | + |
| 252 | + function convertMatrixToHtml( $matrix, $rankedIds ) { |
| 253 | + $abbrevs = $this->getOptionAbbreviations(); |
| 254 | + $rowLabels = $this->getRowLabels( 'html' ); |
| 255 | + |
| 256 | + $s = "<table class=\"securepoll-results\">"; |
| 257 | + |
| 258 | + # Corner box |
| 259 | + $s .= "<tr>\n<th> </th>\n"; |
| 260 | + |
| 261 | + # Header row |
| 262 | + foreach ( $rankedIds as $oid ) { |
| 263 | + $s .= Xml::element( 'th', array(), $abbrevs[$oid] ) . "\n"; |
| 264 | + } |
| 265 | + $s .= "</tr>\n"; |
| 266 | + |
| 267 | + foreach ( $rankedIds as $oid1 ) { |
| 268 | + # Header column |
| 269 | + $s .= "<tr>\n"; |
| 270 | + $s .= Xml::element( 'td', array( 'class' => 'securepoll-results-row-heading' ), |
| 271 | + $rowLabels[$oid1] ); |
| 272 | + # Rest of the matrix |
| 273 | + foreach ( $rankedIds as $oid2 ) { |
| 274 | + if ( isset( $matrix[$oid1][$oid2] ) ) { |
| 275 | + $value = $matrix[$oid1][$oid2]; |
| 276 | + } else { |
| 277 | + $value = ''; |
| 278 | + } |
| 279 | + if ( is_array( $value ) ) { |
| 280 | + $value = '(' . implode( ', ', $value ) . ')'; |
| 281 | + } |
| 282 | + $s .= Xml::element( 'td', array(), $value ) . "\n"; |
84 | 283 | } |
85 | | - $s .= "</table>\n"; |
| 284 | + $s .= "</tr>\n"; |
86 | 285 | } |
| 286 | + $s .= "</table>"; |
| 287 | + } |
| 288 | + |
| 289 | + function convertMatrixToText( $matrix, $rankedIds ) { |
| 290 | + $abbrevs = $this->getOptionAbbreviations(); |
| 291 | + $minWidth = 15; |
| 292 | + $rowLabels = $this->getRowLabels( 'text' ); |
| 293 | + |
| 294 | + # Calculate column widths |
| 295 | + $colWidths = array(); |
| 296 | + foreach ( $abbrevs as $id => $abbrev ) { |
| 297 | + if ( strlen( $abbrev ) < $minWidth ) { |
| 298 | + $colWidths[$id] = $minWidth; |
| 299 | + } else { |
| 300 | + $colWidths[$id] = strlen( $abbrev ); |
| 301 | + } |
| 302 | + } |
| 303 | + $headerColumnWidth = $minWidth; |
| 304 | + foreach ( $rowLabels as $label ) { |
| 305 | + $headerColumnWidth = max( $headerColumnWidth, strlen( $label ) ); |
| 306 | + } |
| 307 | + |
| 308 | + # Corner box |
| 309 | + $s = str_repeat( ' ', $headerColumnWidth ) . ' | '; |
| 310 | + |
| 311 | + # Header row |
| 312 | + foreach ( $rankedIds as $oid ) { |
| 313 | + $s .= str_pad( $abbrevs[$oid], $colWidths[$oid] ) . ' | '; |
| 314 | + } |
| 315 | + $s .= "\n"; |
| 316 | + |
| 317 | + # Divider |
| 318 | + $s .= str_repeat( '-', $headerColumnWidth ) . '-+-'; |
| 319 | + foreach ( $rankedIds as $oid ) { |
| 320 | + $s .= str_repeat( '-', $colWidths[$oid] ) . '-+-'; |
| 321 | + } |
| 322 | + $s .= "\n"; |
| 323 | + |
| 324 | + foreach ( $rankedIds as $oid1 ) { |
| 325 | + # Header column |
| 326 | + $s .= str_pad( $rowLabels[$oid1], $headerColumnWidth ) . ' | '; |
| 327 | + |
| 328 | + # Rest of the matrix |
| 329 | + foreach ( $rankedIds as $oid2 ) { |
| 330 | + if ( isset( $matrix[$oid1][$oid2] ) ) { |
| 331 | + $value = $matrix[$oid1][$oid2]; |
| 332 | + } else { |
| 333 | + $value = ''; |
| 334 | + } |
| 335 | + if ( is_array( $value ) ) { |
| 336 | + $value = '(' . implode( ', ', $value ) . ')'; |
| 337 | + } |
| 338 | + $s .= str_pad( $value, $colWidths[$oid2] ) . ' | '; |
| 339 | + } |
| 340 | + $s .= "\n"; |
| 341 | + } |
87 | 342 | return $s; |
88 | 343 | } |
| 344 | + |
89 | 345 | } |
| 346 | + |
| 347 | + |
| 348 | + |
| 349 | +/** |
| 350 | + * A tallier which gives a tie-breaking ranking of candidates (TBRC) by |
| 351 | + * selecting random preferential votes |
| 352 | + */ |
| 353 | +abstract class SecurePoll_RandomPrefVoteTallier { |
| 354 | + var $records, $random; |
| 355 | + |
| 356 | + function addVote( $vote ) { |
| 357 | + $this->records[] = $vote; |
| 358 | + } |
| 359 | + |
| 360 | + function getTBRCMatrix() { |
| 361 | + $tbrc = array(); |
| 362 | + $marked = array(); |
| 363 | + |
| 364 | + $random = $this->context->getRandom(); |
| 365 | + $status = $random->open(); |
| 366 | + if ( !$status->isOK() ) { |
| 367 | + throw new MWException( "Unable to open random device for TBRC ranking" ); |
| 368 | + } |
| 369 | + |
| 370 | + # Random ballot round |
| 371 | + $numCands = count( $this->optionIds ); |
| 372 | + $numPairsRanked = 0; |
| 373 | + $numRecordsUsed = 0; |
| 374 | + while ( $numRecordsUsed < count( $this->records ) |
| 375 | + && $numPairsRanked < $numCands * $numCands ) |
| 376 | + { |
| 377 | + # Pick the record |
| 378 | + $recordIndex = $random->getInt( $numCands - $numRecordsUsed ); |
| 379 | + $ranks = $this->records[$recordIndex]; |
| 380 | + $numRecordsUsed++; |
| 381 | + |
| 382 | + # Swap it to the end |
| 383 | + $destIndex = $numCands - $numRecordsUsed; |
| 384 | + $this->records[$recordIndex] = $this->records[$destIndex]; |
| 385 | + $this->records[$destIndex] = $ranks; |
| 386 | + |
| 387 | + # Apply its rankings |
| 388 | + foreach ( $this->optionIds as $oid1 ) { |
| 389 | + if ( !isset( $ranks[$oid1] ) ) { |
| 390 | + throw new MWException( "Invalid vote record, missing option $oid1" ); |
| 391 | + } |
| 392 | + foreach ( $this->optionIds as $oid2 ) { |
| 393 | + if ( isset( $marked[$oid1][$oid2] ) ) { |
| 394 | + // Already ranked |
| 395 | + continue; |
| 396 | + } |
| 397 | + |
| 398 | + if ( $oid1 == $oid2 ) { |
| 399 | + # Same candidate, no win |
| 400 | + $tbrc[$oid1][$oid2] = false; |
| 401 | + } elseif ( $ranks[$oid1] < $ranks[$oid2] ) { |
| 402 | + # oid1 win |
| 403 | + $tbrc[$oid1][$oid2] = true; |
| 404 | + } elseif ( $ranks[$oid2] < $ranks[$oid1] ) { |
| 405 | + # oid2 win |
| 406 | + $tbrc[$oid1][$oid2] = false; |
| 407 | + } else { |
| 408 | + # Tie, don't mark |
| 409 | + continue; |
| 410 | + } |
| 411 | + $marked[$oid1][$oid2] = true; |
| 412 | + $numPairsRanked++; |
| 413 | + } |
| 414 | + } |
| 415 | + } |
| 416 | + |
| 417 | + # Random win round |
| 418 | + if ( $numPairsRanked < $numCands * $numCands ) { |
| 419 | + $randomRanks = $random->shuffle( $this->optionIds ); |
| 420 | + foreach ( $randomRanks as $oidWin ) { |
| 421 | + if ( $numPairsRanked >= $numCands * $numCands ) { |
| 422 | + # Done |
| 423 | + break; |
| 424 | + } |
| 425 | + foreach ( $this->optionIds as $oidOther ) { |
| 426 | + if ( !isset( $marked[$oidWin][$oidOther] ) ) { |
| 427 | + $tbrc[$oidWin][$oidOther] = true; |
| 428 | + $marked[$oidWin][$oidOther] = true; |
| 429 | + $numPairsRanked++; |
| 430 | + } |
| 431 | + if ( !isset( $marked[$oidOther][$oidWin] ) ) { |
| 432 | + $tbrc[$oidOther][$oidWin] = false; |
| 433 | + $marked[$oidOther][$oidWin] = true; |
| 434 | + $numPairsRanked++; |
| 435 | + } |
| 436 | + } |
| 437 | + } |
| 438 | + } |
| 439 | + |
| 440 | + return $tbrc; |
| 441 | + } |
| 442 | +} |
| 443 | + |
| 444 | +/** |
| 445 | + * This is the basic Schulze method with no tie-breaking. |
| 446 | + */ |
| 447 | +class SecurePoll_SchulzeTallier extends SecurePoll_PairwiseTallier { |
| 448 | + function getPathStrengths( $victories ) { |
| 449 | + # This algorithm follows Markus Schulze, "A New Monotonic, Clone-Independent, Reversal |
| 450 | + # Symmetric, and Condorcet-Consistent Single-Winner Election Method" and also |
| 451 | + # http://en.wikipedia.org/w/index.php?title=User:MarkusSchulze/Statutory_Rules&oldid=303036893 |
| 452 | + # |
| 453 | + # Path strengths in the Schulze method are given by pairs of integers notated (a, b) |
| 454 | + # where a is the strength in one direction and b is the strength in the other. We make |
| 455 | + # a matrix of path strength pairs "p", giving the path strength of the row index beating |
| 456 | + # the column index. |
| 457 | + |
| 458 | + # First the path strength matrix is populated with the "direct" victory count in each |
| 459 | + # direction, i.e. the number of people who preferenced A over B, and B over A. |
| 460 | + $strengths = array(); |
| 461 | + foreach ( $this->optionIds as $oid1 ) { |
| 462 | + foreach ( $this->optionIds as $oid2 ) { |
| 463 | + if ( $oid1 === $oid2 ) { |
| 464 | + continue; |
| 465 | + } |
| 466 | + $v12 = $victories[$oid1][$oid2]; |
| 467 | + $v21 = $victories[$oid2][$oid1]; |
| 468 | + if ( $v12 > $v21 ) { |
| 469 | + # Direct victory |
| 470 | + $strengths[$oid1][$oid2] = array( $v12, $v21 ); |
| 471 | + } else { |
| 472 | + # Direct loss |
| 473 | + $strengths[$oid1][$oid2] = array( 0, 0 ); |
| 474 | + } |
| 475 | + } |
| 476 | + } |
| 477 | + |
| 478 | + # Next (continuing the Floyd-Warshall algorithm) we calculate the strongest indirect |
| 479 | + # paths. This part dominates the O(N^3) time order. |
| 480 | + foreach ( $this->optionIds as $oid1 ) { |
| 481 | + foreach ( $this->optionIds as $oid2 ) { |
| 482 | + if ( $oid1 === $oid2 ) { |
| 483 | + continue; |
| 484 | + } |
| 485 | + foreach ( $this->optionIds as $oid3 ) { |
| 486 | + if ( $oid1 === $oid3 || $oid2 === $oid3 ) { |
| 487 | + continue; |
| 488 | + } |
| 489 | + $s21 = $strengths[$oid2][$oid1]; |
| 490 | + $s13 = $strengths[$oid1][$oid3]; |
| 491 | + $s23 = $strengths[$oid2][$oid3]; |
| 492 | + if ( $this->isSchulzeWin( $s21, $s13 ) ) { |
| 493 | + $temp = $s13; |
| 494 | + } else { |
| 495 | + $temp = $s21; |
| 496 | + } |
| 497 | + if ( $this->isSchulzeWin( $temp, $s23 ) ) { |
| 498 | + $strengths[$oid2][$oid3] = $temp; |
| 499 | + } |
| 500 | + } |
| 501 | + } |
| 502 | + } |
| 503 | + |
| 504 | + return $strengths; |
| 505 | + } |
| 506 | + |
| 507 | + function convertStrengthMatrixToRanks( $strengths ) { |
| 508 | + $unusedIds = $this->optionIds; |
| 509 | + $ranks = array(); |
| 510 | + $currentRank = 1; |
| 511 | + |
| 512 | + while ( count( $unusedIds ) ) { |
| 513 | + $winners = array_flip( $unusedIds ); |
| 514 | + foreach ( $unusedIds as $oid1 ) { |
| 515 | + foreach ( $unusedIds as $oid2 ) { |
| 516 | + if ( $oid1 == $oid2 ) { |
| 517 | + continue; |
| 518 | + } |
| 519 | + $s12 = $strengths[$oid1][$oid2]; |
| 520 | + $s21 = $strengths[$oid2][$oid1]; |
| 521 | + if ( $this->isSchulzeWin( $s21, $s12 ) ) { |
| 522 | + # oid1 is defeated by someone, not a winner |
| 523 | + unset( $winners[$oid1] ); |
| 524 | + break; |
| 525 | + } |
| 526 | + } |
| 527 | + } |
| 528 | + if ( !count( $winners ) ) { |
| 529 | + # No winners, everyone ties for this position |
| 530 | + $winners = array_flip( $unusedIds ); |
| 531 | + } |
| 532 | + |
| 533 | + # Now $winners is the list of candidates that tie for this position |
| 534 | + foreach ( $winners as $oid => $unused ) { |
| 535 | + $ranks[$oid] = $currentRank; |
| 536 | + } |
| 537 | + $currentRank += count( $winners ); |
| 538 | + $unusedIds = array_diff( $unusedIds, array_keys( $winners ) ); |
| 539 | + } |
| 540 | + return $ranks; |
| 541 | + } |
| 542 | + |
| 543 | + /** |
| 544 | + * Determine whether Schulze's win relation "s1 >win s2" for path strength |
| 545 | + * pairs s1 and s2 is satisfied. |
| 546 | + * |
| 547 | + * When applied to final path strengths instead of intermediate results, |
| 548 | + * the paper notates this relation >D (greater than subscript D). |
| 549 | + * |
| 550 | + * The inequality in the second part is reversed because the first part |
| 551 | + * refers to wins, and the second part refers to losses. |
| 552 | + */ |
| 553 | + function isSchulzeWin( $s1, $s2 ) { |
| 554 | + return $s1[0] > $s2[0] || ( $s1[0] == $s2[0] && $s1[1] < $s2[1] ); |
| 555 | + } |
| 556 | + |
| 557 | + function finishTally() { |
| 558 | + $this->strengths = $this->getPathStrengths( $this->victories ); |
| 559 | + $this->ranks = $this->convertStrengthMatrixToRanks( $this->strengths ); |
| 560 | + } |
| 561 | + |
| 562 | + function getRanks() { |
| 563 | + return $this->ranks; |
| 564 | + } |
| 565 | + |
| 566 | + function getHtmlResult() { |
| 567 | + global $wgOut; |
| 568 | + $s = $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-ranks' ) . "</h2>\n" ); |
| 569 | + $s .= $this->convertRanksToHtml( $this->ranks ); |
| 570 | + |
| 571 | + $s = $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-pairwise-victories' ) . "</h2>\n" ); |
| 572 | + $rankedIds = array_keys( $this->ranks ); |
| 573 | + $s .= $this->convertMatrixToHtml( $this->victories, $rankedIds ); |
| 574 | + |
| 575 | + $s .= $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-strength-matrix' ) . "</h2>\n" ); |
| 576 | + $s .= $this->convertMatrixToHtml( $this->strengths, $rankedIds ); |
| 577 | + return $s; |
| 578 | + } |
| 579 | + |
| 580 | + function getTextResult() { |
| 581 | + $rankedIds = array_keys( $this->ranks ); |
| 582 | + |
| 583 | + return |
| 584 | + wfMsg( 'securepoll-ranks' ) . "\n" . |
| 585 | + $this->convertRanksToText( $this->ranks ) . "\n\n" . |
| 586 | + wfMsg( 'securepoll-pairwise-victories' ). "\n" . |
| 587 | + $this->convertMatrixToText( $this->victories, $rankedIds ) . "\n\n" . |
| 588 | + wfMsg( 'securepoll-strength-matrix' ) . "\n" . |
| 589 | + $this->convertMatrixToText( $this->strengths, $rankedIds ); |
| 590 | + } |
| 591 | +} |
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Voter.php |
— | — | @@ -13,7 +13,8 @@ |
14 | 14 | /** |
15 | 15 | * Create a voter from the given associative array of parameters |
16 | 16 | */ |
17 | | - function __construct( $params ) { |
| 17 | + function __construct( $context, $params ) { |
| 18 | + $this->context = $context; |
18 | 19 | foreach ( self::$paramNames as $name ) { |
19 | 20 | if ( isset( $params[$name] ) ) { |
20 | 21 | $this->$name = $params[$name]; |
— | — | @@ -25,20 +26,20 @@ |
26 | 27 | * Create a voter object from the database |
27 | 28 | * @return SecurePoll_Voter or false if the ID is not valid |
28 | 29 | */ |
29 | | - static function newFromId( $id ) { |
30 | | - $db = wfGetDB( DB_MASTER ); |
| 30 | + static function newFromId( $context, $id ) { |
| 31 | + $db = $context->getDB(); |
31 | 32 | $row = $db->selectRow( 'securepoll_voters', '*', array( 'voter_id' => $id ), __METHOD__ ); |
32 | 33 | if ( !$row ) { |
33 | 34 | return false; |
34 | 35 | } |
35 | | - return self::newFromRow( $row ); |
| 36 | + return self::newFromRow( $context, $row ); |
36 | 37 | } |
37 | 38 | |
38 | 39 | /** |
39 | 40 | * Create a voter from a DB result row |
40 | 41 | */ |
41 | | - static function newFromRow( $row ) { |
42 | | - return new self( array( |
| 42 | + static function newFromRow( $context, $row ) { |
| 43 | + return new self( $context, array( |
43 | 44 | 'id' => $row->voter_id, |
44 | 45 | 'electionId' => $row->voter_election, |
45 | 46 | 'name' => $row->voter_name, |
— | — | @@ -56,8 +57,8 @@ |
57 | 58 | * The row needs to be locked before this function is called, to avoid |
58 | 59 | * duplicate key errors. |
59 | 60 | */ |
60 | | - static function createVoter( $params ) { |
61 | | - $db = wfGetDB( DB_MASTER ); |
| 61 | + static function createVoter( $context, $params ) { |
| 62 | + $db = $context->getDB(); |
62 | 63 | $id = $db->nextSequenceValue( 'voters_voter_id' ); |
63 | 64 | $row = array( |
64 | 65 | 'voter_id' => $id, |
— | — | @@ -70,7 +71,7 @@ |
71 | 72 | ); |
72 | 73 | $db->insert( 'securepoll_voters', $row, __METHOD__ ); |
73 | 74 | $params['id'] = $db->insertId(); |
74 | | - return new self( $params ); |
| 75 | + return new self( $context, $params ); |
75 | 76 | } |
76 | 77 | |
77 | 78 | /** Get the voter ID */ |
— | — | @@ -152,13 +153,13 @@ |
153 | 154 | if ( isset( $_COOKIE[$cookieName] ) ) { |
154 | 155 | $otherVoterId = intval( $_COOKIE[$cookieName] ); |
155 | 156 | if ( $otherVoterId != $this->getId() ) { |
156 | | - $otherVoter = self::newFromId( $otherVoterId ); |
157 | | - if ( $otherVoter->getElectionId() == $this->getElectionId() ) { |
| 157 | + $otherVoter = self::newFromId( $this->context, $otherVoterId ); |
| 158 | + if ( $otherVoter && $otherVoter->getElectionId() == $this->getElectionId() ) { |
158 | 159 | $this->addCookieDup( $otherVoterId ); |
159 | 160 | } |
160 | 161 | } |
161 | 162 | } else { |
162 | | - setcookie( $cookieName, $this->getId(), time() + 86400*3 ); |
| 163 | + setcookie( $cookieName, $this->getId(), time() + 86400*30 ); |
163 | 164 | } |
164 | 165 | } |
165 | 166 | |
— | — | @@ -166,7 +167,7 @@ |
167 | 168 | * Flag a duplicate voter |
168 | 169 | */ |
169 | 170 | function addCookieDup( $voterId ) { |
170 | | - $dbw = wfGetDB( DB_MASTER ); |
| 171 | + $dbw = $this->context->getDB(); |
171 | 172 | # Insert the log record |
172 | 173 | $dbw->insert( 'securepoll_cookie_match', |
173 | 174 | array( |
Index: branches/wmf-deployment/extensions/SecurePoll/cli/cli.inc |
— | — | @@ -0,0 +1,16 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +$IP = getenv( 'MW_INSTALL_PATH' ); |
| 5 | +if ( strval( $IP ) === '' ) { |
| 6 | + $IP = dirname( __FILE__ ).'/../../..'; |
| 7 | +} |
| 8 | +if ( !file_exists( "$IP/includes/WebStart.php" ) ) { |
| 9 | + $IP .= '/phase3'; |
| 10 | +} |
| 11 | +if ( !file_exists( "$IP/includes/WebStart.php" ) ) { |
| 12 | + echo "Can't find your MediaWiki installation. Please set the MW_INSTALL_PATH environment variable.\n"; |
| 13 | + exit( 1 ); |
| 14 | +} |
| 15 | + |
| 16 | +require( $IP . '/maintenance/commandLine.inc' ); |
| 17 | + |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/cli/cli.inc |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 18 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/cli/import.php |
— | — | @@ -0,0 +1,257 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +require( dirname( __FILE__ ) . '/cli.inc' ); |
| 5 | + |
| 6 | +$usage = <<<EOT |
| 7 | +Import configuration files into the local SecurePoll database. Files can be |
| 8 | +generated with dump.php. |
| 9 | + |
| 10 | +Usage: import.php [options] <file> |
| 11 | + |
| 12 | +Options are: |
| 13 | + --update-msgs Update the internationalised text for the elections, do |
| 14 | + not update configuration. |
| 15 | + |
| 16 | + --replace If an election with a conflicting title exists already, |
| 17 | + replace it, updating its configuration. The default is |
| 18 | + to exit with an error. |
| 19 | + |
| 20 | +Note that any vote records will NOT be imported. |
| 21 | + |
| 22 | +For the moment, the entity IDs are preserved, to allow easier implementation of |
| 23 | +the message update feature. This means conflicting entity IDs in the local |
| 24 | +database will generate an error. This restriction will be removed in the |
| 25 | +future. |
| 26 | + |
| 27 | +EOT; |
| 28 | + |
| 29 | +# Most of the code here will eventually be refactored into the update interfaces |
| 30 | +# of the entity and context classes, but that project can wait until we have a |
| 31 | +# setup UI. |
| 32 | + |
| 33 | +if ( !isset( $args[0] ) ) { |
| 34 | + echo $usage; |
| 35 | + exit( 1 ); |
| 36 | +} |
| 37 | +if ( !file_exists( $args[0] ) ) { |
| 38 | + echo "The specified file \"{$args[0]}\" does not exist\n"; |
| 39 | + exit( 1 ); |
| 40 | +} |
| 41 | + |
| 42 | +foreach ( array( 'update-msgs', 'replace' ) as $optName ) { |
| 43 | + if ( !isset( $options[$optName] ) ) { |
| 44 | + $options[$optName] = false; |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +$success = spImportDump( $args[0], $options ); |
| 49 | +exit( $success ? 0 : 1 ); |
| 50 | + |
| 51 | +function spImportDump( $fileName, $options ) { |
| 52 | + $store = new SecurePoll_XMLStore( $fileName ); |
| 53 | + $success = $store->readFile(); |
| 54 | + if ( !$success ) { |
| 55 | + echo "Error reading XML dump, possibly corrupt\n"; |
| 56 | + return false; |
| 57 | + } |
| 58 | + $electionIds = $store->getAllElectionIds(); |
| 59 | + if ( !count( $electionIds ) ) { |
| 60 | + echo "No elections found to import.\n"; |
| 61 | + return true; |
| 62 | + } |
| 63 | + |
| 64 | + $xc = new SecurePoll_Context; |
| 65 | + $xc->setStore( $store ); |
| 66 | + $dbw = wfGetDB( DB_MASTER ); |
| 67 | + |
| 68 | + # Start the configuration transaction |
| 69 | + $dbw->begin(); |
| 70 | + foreach ( $electionIds as $id ) { |
| 71 | + $elections = $store->getElectionInfo( array( $id ) ); |
| 72 | + $electionInfo = reset( $elections ); |
| 73 | + $existingId = $dbw->selectField( |
| 74 | + 'securepoll_elections', |
| 75 | + 'el_entity', |
| 76 | + array( 'el_title' => $electionInfo['title'] ), |
| 77 | + __METHOD__, |
| 78 | + array( 'FOR UPDATE' ) ); |
| 79 | + if ( $existingId !== false ) { |
| 80 | + if ( $options['replace'] ) { |
| 81 | + spDeleteElection( $existingId ); |
| 82 | + $success = spImportConfiguration( $store, $electionInfo ); |
| 83 | + } elseif ( $options['update-msgs'] ) { |
| 84 | + # Do the message update and move on to the next election |
| 85 | + $success = spUpdateMessages( $store, $electionInfo ); |
| 86 | + } else { |
| 87 | + echo "Conflicting election title found \"{$electionInfo['title']}\"\n"; |
| 88 | + echo "Use --replace to replace the existing election.\n"; |
| 89 | + $success = false; |
| 90 | + } |
| 91 | + } elseif ( $options['update-msgs'] ) { |
| 92 | + echo "Cannot update messages: election \"{$electionInfo['title']}\" not found.\n"; |
| 93 | + echo "Import the configuration first, without the --update-msgs switch.\n"; |
| 94 | + $success = false; |
| 95 | + } else { |
| 96 | + $success = spImportConfiguration( $store, $electionInfo ); |
| 97 | + } |
| 98 | + if ( !$success ) { |
| 99 | + $dbw->rollback(); |
| 100 | + return false; |
| 101 | + } |
| 102 | + } |
| 103 | + $dbw->commit(); |
| 104 | + return true; |
| 105 | +} |
| 106 | + |
| 107 | +function spDeleteElection( $electionId ) { |
| 108 | + $dbw = wfGetDB( DB_MASTER ); |
| 109 | + |
| 110 | + # Get a list of entity IDs and lock them |
| 111 | + $questionIds = array(); |
| 112 | + $res = $dbw->select( 'securepoll_questions', array( 'qu_entity' ), |
| 113 | + array( 'qu_election' => $electionId ), |
| 114 | + __METHOD__, array( 'FOR UPDATE' ) ); |
| 115 | + foreach ( $res as $row ) { |
| 116 | + $questionIds[] = $row->qu_entity; |
| 117 | + } |
| 118 | + |
| 119 | + $res = $dbw->select( 'securepoll_options', array( 'op_entity' ), |
| 120 | + array( 'op_election' => $electionId ), |
| 121 | + __METHOD__, array( 'FOR UPDATE' ) ); |
| 122 | + $optionIds = array(); |
| 123 | + foreach ( $res as $row ) { |
| 124 | + $optionIds[] = $row->op_entity; |
| 125 | + } |
| 126 | + |
| 127 | + $entityIds = array_merge( $optionIds, $questionIds, array( $electionId ) ); |
| 128 | + |
| 129 | + # Delete the messages and properties |
| 130 | + $dbw->delete( 'securepoll_msgs', array( 'msg_entity' => $entityIds ) ); |
| 131 | + $dbw->delete( 'securepoll_properties', array( 'pr_entity' => $entityIds ) ); |
| 132 | + |
| 133 | + # Delete the entities |
| 134 | + $dbw->delete( 'securepoll_options', array( 'op_entity' => $optionIds ), __METHOD__ ); |
| 135 | + $dbw->delete( 'securepoll_questions', array( 'qu_entity' => $questionIds ), __METHOD__ ); |
| 136 | + $dbw->delete( 'securepoll_elections', array( 'el_entity' => $electionId ), __METHOD__ ); |
| 137 | + $dbw->delete( 'securepoll_entity', array( 'en_id' => $entityIds ), __METHOD__ ); |
| 138 | +} |
| 139 | + |
| 140 | +function spInsertEntity( $type, $id ) { |
| 141 | + $dbw = wfGetDB( DB_MASTER ); |
| 142 | + $dbw->insert( 'securepoll_entity', |
| 143 | + array( |
| 144 | + 'en_id' => $id, |
| 145 | + 'en_type' => $type, |
| 146 | + ), |
| 147 | + __METHOD__ |
| 148 | + ); |
| 149 | +} |
| 150 | + |
| 151 | +function spImportConfiguration( $store, $electionInfo ) { |
| 152 | + $dbw = wfGetDB( DB_MASTER ); |
| 153 | + $sourceIds = array(); |
| 154 | + |
| 155 | + # Election |
| 156 | + spInsertEntity( 'election', $electionInfo['id'] ); |
| 157 | + $dbw->insert( 'securepoll_elections', |
| 158 | + array( |
| 159 | + 'el_entity' => $electionInfo['id'], |
| 160 | + 'el_title' => $electionInfo['title'], |
| 161 | + 'el_ballot' => $electionInfo['ballot'], |
| 162 | + 'el_tally' => $electionInfo['tally'], |
| 163 | + 'el_primary_lang' => $electionInfo['primaryLang'], |
| 164 | + 'el_start_date' => $dbw->timestamp( $electionInfo['startDate'] ), |
| 165 | + 'el_end_date' => $dbw->timestamp( $electionInfo['endDate'] ), |
| 166 | + 'el_auth_type' => $electionInfo['auth'] |
| 167 | + ), |
| 168 | + __METHOD__ ); |
| 169 | + $sourceIds[] = $electionInfo['id']; |
| 170 | + |
| 171 | + |
| 172 | + # Questions |
| 173 | + $index = 1; |
| 174 | + foreach ( $electionInfo['questions'] as $questionInfo ) { |
| 175 | + spInsertEntity( 'question', $questionInfo['id'] ); |
| 176 | + $dbw->insert( 'securepoll_questions', |
| 177 | + array( |
| 178 | + 'qu_entity' => $questionInfo['id'], |
| 179 | + 'qu_election' => $electionInfo['id'], |
| 180 | + 'qu_index' => $index++, |
| 181 | + ), |
| 182 | + __METHOD__ ); |
| 183 | + $sourceIds[] = $questionInfo['id']; |
| 184 | + |
| 185 | + # Options |
| 186 | + $insertBatch = array(); |
| 187 | + foreach ( $questionInfo['options'] as $optionInfo ) { |
| 188 | + spInsertEntity( 'option', $optionInfo['id'] ); |
| 189 | + $insertBatch[] = array( |
| 190 | + 'op_entity' => $optionInfo['id'], |
| 191 | + 'op_election' => $electionInfo['id'], |
| 192 | + 'op_question' => $questionInfo['id'] |
| 193 | + ); |
| 194 | + $sourceIds[] = $optionInfo['id']; |
| 195 | + } |
| 196 | + $dbw->insert( 'securepoll_options', $insertBatch, __METHOD__ ); |
| 197 | + } |
| 198 | + |
| 199 | + # Messages |
| 200 | + spInsertMessages( $store, $sourceIds ); |
| 201 | + |
| 202 | + # Properties |
| 203 | + $properties = $store->getProperties( $sourceIds ); |
| 204 | + $insertBatch = array(); |
| 205 | + foreach ( $properties as $id => $entityProps ) { |
| 206 | + foreach ( $entityProps as $key => $value ) { |
| 207 | + $insertBatch[] = array( |
| 208 | + 'pr_entity' => $id, |
| 209 | + 'pr_key' => $key, |
| 210 | + 'pr_value' => $value |
| 211 | + ); |
| 212 | + } |
| 213 | + } |
| 214 | + if ( $insertBatch ) { |
| 215 | + $dbw->insert( 'securepoll_properties', $insertBatch, __METHOD__ ); |
| 216 | + } |
| 217 | + return true; |
| 218 | +} |
| 219 | + |
| 220 | +function spInsertMessages( $store, $entityIds ) { |
| 221 | + $langs = $store->getLangList( $entityIds ); |
| 222 | + $insertBatch = array(); |
| 223 | + foreach ( $langs as $lang ) { |
| 224 | + $messages = $store->getMessages( $lang, $entityIds ); |
| 225 | + foreach ( $messages as $id => $entityMsgs ) { |
| 226 | + foreach ( $entityMsgs as $key => $text ) { |
| 227 | + $insertBatch[] = array( |
| 228 | + 'msg_entity' => $id, |
| 229 | + 'msg_lang' => $lang, |
| 230 | + 'msg_key' => $key, |
| 231 | + 'msg_text' => $text |
| 232 | + ); |
| 233 | + } |
| 234 | + } |
| 235 | + } |
| 236 | + if ( $insertBatch ) { |
| 237 | + $dbw = wfGetDB( DB_MASTER ); |
| 238 | + $dbw->insert( 'securepoll_msgs', $insertBatch, __METHOD__ ); |
| 239 | + } |
| 240 | +} |
| 241 | + |
| 242 | +function spUpdateMessages( $store, $electionInfo ) { |
| 243 | + $entityIds = array( $electionInfo['id'] ); |
| 244 | + foreach ( $electionInfo['questions'] as $questionInfo ) { |
| 245 | + $entityIds[] = $questionInfo['id']; |
| 246 | + foreach ( $questionInfo['options'] as $optionInfo ) { |
| 247 | + $entityIds[] = $optionInfo['id']; |
| 248 | + } |
| 249 | + } |
| 250 | + |
| 251 | + # Delete existing messages |
| 252 | + $dbw = wfGetDB( DB_MASTER ); |
| 253 | + $dbw->delete( 'securepoll_msgs', array( 'msg_entity' => $entityIds ), __METHOD__ ); |
| 254 | + |
| 255 | + # Insert new messages |
| 256 | + spInsertMessages( $store, $entityIds ); |
| 257 | +} |
| 258 | + |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/cli/import.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 259 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/cli/testDebian.php |
— | — | @@ -0,0 +1,175 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +require( dirname(__FILE__).'/cli.inc' ); |
| 5 | +$testDir = dirname(__FILE__).'/debtest'; |
| 6 | +if ( !is_dir( $testDir ) ) { |
| 7 | + mkdir( $testDir ); |
| 8 | +} |
| 9 | + |
| 10 | +$spDebianVoteDir = '/home/tstarling/src/voting/debian-vote/debian-vote-0.8-fixed'; |
| 11 | + |
| 12 | +if ( count( $args ) ) { |
| 13 | + foreach ( $args as $arg ) { |
| 14 | + if ( !file_exists( $arg ) ) { |
| 15 | + echo "File not found: $arg\n"; |
| 16 | + exit( 1 ); |
| 17 | + } |
| 18 | + $debResult = spRunDebianVote( $arg ); |
| 19 | + if ( spRunTest( $arg, $debResult ) ) { |
| 20 | + echo "$arg OK\n"; |
| 21 | + } |
| 22 | + } |
| 23 | + exit( 0 ); |
| 24 | +} |
| 25 | + |
| 26 | +for ( $i = 1; true; $i++ ) { |
| 27 | + $fileName = "$testDir/$i.in"; |
| 28 | + spGenerateTest( $fileName ); |
| 29 | + $debResult = spRunDebianVote( $fileName ); |
| 30 | + if ( spRunTest( $fileName, $debResult ) ) { |
| 31 | + unlink( $fileName ); |
| 32 | + } |
| 33 | + if ( $i % 1000 == 0 ) { |
| 34 | + echo "$i tests done\n"; |
| 35 | + } |
| 36 | +} |
| 37 | + |
| 38 | +function spRunTest( $fileName, $debResult ) { |
| 39 | + $file = fopen( $fileName, 'r' ); |
| 40 | + if ( !$file ) { |
| 41 | + echo "Unable to open file \"$fileName\" for input\n"; |
| 42 | + return; |
| 43 | + } |
| 44 | + |
| 45 | + $votes = array(); |
| 46 | + $numCands = 0; |
| 47 | + while ( !feof( $file ) ) { |
| 48 | + $line = fgets( $file ); |
| 49 | + if ( $line === false ) { |
| 50 | + break; |
| 51 | + } |
| 52 | + $line = trim( $line ); |
| 53 | + if ( !preg_match( '/^V: ([0-9-]*)$/', $line, $m ) ) { |
| 54 | + echo "Skipping unrecognised line $line\n"; |
| 55 | + continue; |
| 56 | + } |
| 57 | + |
| 58 | + $record = array(); |
| 59 | + for ( $i = 0; $i < strlen( $m[1] ); $i++ ) { |
| 60 | + $pref = substr( $m[1], $i, 1 ); |
| 61 | + if ( $i == strlen( $m[1] ) - 1 ) { |
| 62 | + $id = 'X'; |
| 63 | + } else { |
| 64 | + $id = chr( ord( 'A' ) + $i ); |
| 65 | + } |
| 66 | + if ( $pref === '-' ) { |
| 67 | + $record[$id] = 1000; |
| 68 | + } else { |
| 69 | + $record[$id] = intval( $pref ); |
| 70 | + } |
| 71 | + } |
| 72 | + $votes[] = $record; |
| 73 | + $numCands = max( $numCands, count( $record ) ); |
| 74 | + } |
| 75 | + |
| 76 | + $options = array(); |
| 77 | + for ( $i = 0; $i < $numCands - 1; $i++ ) { |
| 78 | + $id = chr( ord( 'A' ) + $i ); |
| 79 | + $options[$id] = $id; |
| 80 | + } |
| 81 | + $options['X'] = 'X'; |
| 82 | + $question = new SecurePoll_FakeQuestion( $options ); |
| 83 | + $tallier = new SecurePoll_SchulzeTallier( false, $question ); |
| 84 | + foreach ( $votes as $vote ) { |
| 85 | + $tallier->addVote( $vote ); |
| 86 | + } |
| 87 | + $tallier->finishTally(); |
| 88 | + $ranks = $tallier->getRanks(); |
| 89 | + $winners = array(); |
| 90 | + foreach ( $ranks as $oid => $rank ) { |
| 91 | + if ( $rank === 1 ) { |
| 92 | + $winners[] = $oid; |
| 93 | + } |
| 94 | + } |
| 95 | + if ( count( $winners ) > 1 ) { |
| 96 | + $expected = 'result: tie between options ' . implode( ', ', $winners ); |
| 97 | + } else { |
| 98 | + $expected = 'result: option ' . reset( $winners ) . ' wins'; |
| 99 | + } |
| 100 | + if ( $debResult === $expected ) { |
| 101 | + return true; |
| 102 | + } |
| 103 | + |
| 104 | + echo "Mismatch in file $fileName\n"; |
| 105 | + echo "Debian got: $debResult\n"; |
| 106 | + echo "We got: $expected\n\n"; |
| 107 | + echo $tallier->getTextResult(); |
| 108 | + return false; |
| 109 | +} |
| 110 | + |
| 111 | +function spRunDebianVote( $fileName ) { |
| 112 | + global $spDebianVoteDir; |
| 113 | + $result = wfShellExec( |
| 114 | + wfEscapeShellArg( |
| 115 | + "$spDebianVoteDir/debian-vote", |
| 116 | + $fileName |
| 117 | + ) |
| 118 | + ); |
| 119 | + if ( !$result ) { |
| 120 | + echo "Error running debian vote!\n"; |
| 121 | + exit( 1 ); |
| 122 | + } |
| 123 | + $result = rtrim( $result ); |
| 124 | + $lastLineEnd = strrpos( $result, "\n" ); |
| 125 | + $lastLine = substr( $result, $lastLineEnd + 1 ); |
| 126 | + return $lastLine; |
| 127 | +} |
| 128 | + |
| 129 | +function spGetRandom( $min, $max ) { |
| 130 | + return mt_rand( 0, mt_getrandmax() ) / mt_getrandmax() * ( $max - $min ) + $min; |
| 131 | +} |
| 132 | + |
| 133 | +function spGenerateTest( $fileName ) { |
| 134 | + global $spDebianVoteDir; |
| 135 | + wfShellExec( |
| 136 | + wfEscapeShellArg( "$spDebianVoteDir/votegen" ) . ' > ' . |
| 137 | + wfEscapeShellArg( $fileName ) |
| 138 | + ); |
| 139 | +} |
| 140 | + |
| 141 | +class SecurePoll_FakeQuestion { |
| 142 | + var $options; |
| 143 | + |
| 144 | + function __construct( $options ) { |
| 145 | + $this->options = array(); |
| 146 | + foreach ( $options as $i => $option ) { |
| 147 | + $this->options[] = new SecurePoll_FakeOption( $i, $option ); |
| 148 | + } |
| 149 | + } |
| 150 | + |
| 151 | + function getOptions() { |
| 152 | + return $this->options; |
| 153 | + } |
| 154 | +} |
| 155 | + |
| 156 | +class SecurePoll_FakeOption { |
| 157 | + var $id, $name; |
| 158 | + |
| 159 | + function __construct( $id, $name ) { |
| 160 | + $this->id = $id; |
| 161 | + $this->name = $name; |
| 162 | + } |
| 163 | + |
| 164 | + function getMessage( $key ) { |
| 165 | + return $this->name; |
| 166 | + } |
| 167 | + |
| 168 | + function parseMessage( $key ) { |
| 169 | + return htmlspecialchars( $this->name ); |
| 170 | + } |
| 171 | + |
| 172 | + function getId() { |
| 173 | + return $this->id; |
| 174 | + } |
| 175 | +} |
| 176 | + |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/cli/testDebian.php |
___________________________________________________________________ |
Added: svn:mergeinfo |
Added: svn:eol-style |
1 | 177 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/cli/dump.php |
— | — | @@ -0,0 +1,85 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Generate an XML dump of an election, including configuration and votes. |
| 6 | + */ |
| 7 | + |
| 8 | + |
| 9 | +$optionsWithArgs = array( 'o' ); |
| 10 | +require( dirname(__FILE__).'/cli.inc' ); |
| 11 | + |
| 12 | +$usage = <<<EOT |
| 13 | +Usage: php dump.php [options...] <election name> |
| 14 | +Options: |
| 15 | + -o <outfile> Output to the specified file |
| 16 | + --votes Include vote records |
| 17 | + --all-langs Include messages for all languages instead of just the primary |
| 18 | + --jump Produce a configuration dump suitable for setting up a jump wiki |
| 19 | +EOT; |
| 20 | + |
| 21 | +if ( !isset( $args[0] ) ) { |
| 22 | + spFatal( $usage ); |
| 23 | +} |
| 24 | + |
| 25 | +$context = new SecurePoll_Context; |
| 26 | +$election = $context->getElectionByTitle( $args[0] ); |
| 27 | +if ( !$election ) { |
| 28 | + spFatal( "There is no election called \"$args[0]\"" ); |
| 29 | +} |
| 30 | + |
| 31 | +if ( !isset( $options['o'] ) ) { |
| 32 | + $fileName = '-'; |
| 33 | +} else { |
| 34 | + $fileName = $options['o']; |
| 35 | +} |
| 36 | +if ( $fileName === '-' ) { |
| 37 | + $outFile = STDOUT; |
| 38 | +} else { |
| 39 | + $outFile = fopen( $fileName, 'w' ); |
| 40 | +} |
| 41 | +if ( !$outFile ) { |
| 42 | + spFatal( "Unable to open $fileName for writing" ); |
| 43 | +} |
| 44 | + |
| 45 | +if ( isset( $options['all-langs'] ) ) { |
| 46 | + $langs = $election->getLangList(); |
| 47 | +} else { |
| 48 | + $langs = array( $election->getLanguage() ); |
| 49 | +} |
| 50 | +$confXml = $election->getConfXml( array( |
| 51 | + 'jump' => isset( $options['jump'] ), |
| 52 | + 'langs' => $langs |
| 53 | +) ); |
| 54 | + |
| 55 | +$cbdata = array( |
| 56 | + 'header' => "<SecurePoll>\n<election>\n$confXml", |
| 57 | + 'outFile' => $outFile |
| 58 | +); |
| 59 | +$election->cbdata = $cbdata; |
| 60 | + |
| 61 | +# Write vote records |
| 62 | +if ( isset( $options['votes'] ) ) { |
| 63 | + $status = $election->dumpVotesToCallback( 'spDumpVote' ); |
| 64 | + if ( !$status->isOK() ) { |
| 65 | + spFatal( $status->getWikiText() ); |
| 66 | + } |
| 67 | +} |
| 68 | +if ( $election->cbdata['header'] ) { |
| 69 | + fwrite( $outFile, $election->cbdata['header'] ); |
| 70 | +} |
| 71 | + |
| 72 | +fwrite( $outFile, "</election>\n</SecurePoll>\n" ); |
| 73 | + |
| 74 | +function spFatal( $message ) { |
| 75 | + fwrite( STDERR, rtrim( $message ) . "\n" ); |
| 76 | + exit( 1 ); |
| 77 | +} |
| 78 | + |
| 79 | +function spDumpVote( $election, $row ) { |
| 80 | + if ( $election->cbdata['header'] ) { |
| 81 | + fwrite( $election->cbdata['outFile'], $election->cbdata['header'] ); |
| 82 | + $election->cbdata['header'] = false; |
| 83 | + } |
| 84 | + fwrite( $election->cbdata['outFile'], "<vote>" . $row->vote_record . "</vote>\n" ); |
| 85 | +} |
| 86 | + |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/cli/dump.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 87 | + native |
Index: branches/wmf-deployment/extensions/SecurePoll/cli/tally.php |
— | — | @@ -0,0 +1,62 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Tally an election from a dump file or local database. |
| 6 | + * |
| 7 | + * Can be used to tally very large numbers of votes, when the web interface is |
| 8 | + * not feasible. |
| 9 | + */ |
| 10 | + |
| 11 | +$optionsWithArgs = array( 'name' ); |
| 12 | +require( dirname(__FILE__).'/cli.inc' ); |
| 13 | + |
| 14 | +$usage = <<<EOT |
| 15 | +Usage: |
| 16 | + php tally.php [--html] --name <election name> |
| 17 | + php tally.php [--html] <dump file> |
| 18 | +EOT; |
| 19 | + |
| 20 | +if ( !isset( $options['name'] ) && !isset( $args[0] ) ) { |
| 21 | + spFatal( $usage ); |
| 22 | +} |
| 23 | + |
| 24 | +if ( !class_exists( 'SecurePoll_Context' ) ) { |
| 25 | + if ( isset( $options['name'] ) ) { |
| 26 | + spFatal( "Cannot load from database when SecurePoll is not installed" ); |
| 27 | + } |
| 28 | + require( dirname( __FILE__ ) . '/../SecurePoll.php' ); |
| 29 | +} |
| 30 | + |
| 31 | +$context = new SecurePoll_Context; |
| 32 | +if ( !isset( $options['name'] ) ) { |
| 33 | + $context = SecurePoll_Context::newFromXmlFile( $args[0] ); |
| 34 | + if ( !$context ) { |
| 35 | + spFatal( "Unable to parse XML file \"{$args[0]}\"" ); |
| 36 | + } |
| 37 | + $electionIds = $context->getStore()->getAllElectionIds(); |
| 38 | + if ( !count( $electionIds ) ) { |
| 39 | + spFatal( "No elections found in XML file \"{$args[0]}\"" ); |
| 40 | + } |
| 41 | + $election = $context->getElection( reset( $electionIds ) ); |
| 42 | +} else { |
| 43 | + $election = $context->getElectionByTitle( $options['name'] ); |
| 44 | + if ( !$election ) { |
| 45 | + spFatal( "The specified election does not exist." ); |
| 46 | + } |
| 47 | +} |
| 48 | +$status = $election->tally(); |
| 49 | +if ( !$status->isOK() ) { |
| 50 | + spFatal( "Tally error: " . $status->getWikiText() ); |
| 51 | +} |
| 52 | +$tallier = $status->value; |
| 53 | +if ( isset( $options['html'] ) ) { |
| 54 | + echo $tallier->getHtmlResult(); |
| 55 | +} else { |
| 56 | + echo $tallier->getTextResult(); |
| 57 | +} |
| 58 | + |
| 59 | + |
| 60 | +function spFatal( $message ) { |
| 61 | + fwrite( STDERR, rtrim( $message ) . "\n" ); |
| 62 | + exit( 1 ); |
| 63 | +} |
Property changes on: branches/wmf-deployment/extensions/SecurePoll/cli/tally.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 64 | + native |
Property changes on: branches/wmf-deployment/extensions/SecurePoll |
___________________________________________________________________ |
Added: svn:mergeinfo |
2 | 65 | Merged /trunk/phase3/extensions/SecurePoll:r52290,52402,52404,52718,52737,52759,52776,52791,52800,52808,52812-52813,52815-52819,52822,52846,52850,52852-52853,52855-52857,52859,52924,52986,53128-53129,53190,53197,53199,53203-53204,53210-53211,53247,53249,53252,53267,53369 |
3 | 66 | Merged /trunk/phase3/SecurePoll:r52859,53272 |
4 | 67 | Merged /branches/REL1_15/phase3/extensions/SecurePoll:r51646 |
5 | 68 | Merged /trunk/extensions/SecurePoll:r52089-53857 |