diff --git a/.gitignore b/.gitignore index 5e0681cb..8671d442 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ data/ tmp/ # Ignore for safety .htaccess -.htpasswd \ No newline at end of file +.htpasswd +config.inc.php diff --git a/config.inc.php.example b/config.inc.php.example new file mode 100644 index 00000000..b1b82646 --- /dev/null +++ b/config.inc.php.example @@ -0,0 +1,4 @@ +1,'message'=>'Please wait 10 seconds between each post.')); exit; } + { echo json_encode(array('status'=>1,'message'=>translate('Please wait 10 seconds between each post.'))); exit; } // Make sure content is not too big. $data = $_POST['data']; if (strlen($data)>2000000) - { echo json_encode(array('status'=>1,'message'=>'Paste is limited to 2 Mb of encrypted data.')); exit; } + { echo json_encode(array('status'=>1,'message'=>translate('Paste is limited to 2 Mb of encrypted data.'))); exit; } // Make sure format is correct. if (!validSJCL($data)) - { echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; } + { echo json_encode(array('status'=>1,'message'=>translate('Invalid data.'))); exit; } // Read additional meta-information. $meta=array(); @@ -237,7 +260,7 @@ function deletePaste($pasteid) if ($error) { - echo json_encode(array('status'=>1,'message'=>'Invalid data.')); + echo json_encode(array('status'=>1,'message'=>translate('Invalid data.'))); exit; } @@ -255,8 +278,8 @@ function deletePaste($pasteid) { $pasteid = $_POST['pasteid']; $parentid = $_POST['parentid']; - if (!preg_match('/\A[a-f\d]{16}\z/',$pasteid)) { echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; } - if (!preg_match('/\A[a-f\d]{16}\z/',$parentid)) { echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; } + if (!preg_match('/\A[a-f\d]{16}\z/',$pasteid)) { echo json_encode(array('status'=>1,'message'=>translate('Invalid data.'))); exit; } + if (!preg_match('/\A[a-f\d]{16}\z/',$parentid)) { echo json_encode(array('status'=>1,'message'=>translate('Invalid data.'))); exit; } unset($storage['expire_date']); // Comment do not expire (it's the paste that expires) unset($storage['opendiscussion']); @@ -264,18 +287,18 @@ function deletePaste($pasteid) // Make sure paste exists. $storagedir = dataid2path($pasteid); - if (!is_file($storagedir.$pasteid)) { echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; } + if (!is_file($storagedir.$pasteid)) { echo json_encode(array('status'=>1,'message'=>translate('Invalid data.'))); exit; } // Make sure the discussion is opened in this paste. $paste=json_decode(file_get_contents($storagedir.$pasteid)); - if (!$paste->meta->opendiscussion) { echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; } + if (!$paste->meta->opendiscussion) { echo json_encode(array('status'=>1,'message'=>translate('Invalid data.'))); exit; } $discdir = dataid2discussionpath($pasteid); $filename = $pasteid.'.'.$dataid.'.'.$parentid; if (!is_dir($discdir)) mkdir($discdir,$mode=0705,$recursive=true); if (is_file($discdir.$filename)) // Oups... improbable collision. { - echo json_encode(array('status'=>1,'message'=>'You are unlucky. Try again.')); + echo json_encode(array('status'=>1,'message'=>translate('You are unlucky. Try again.'))); exit; } @@ -289,7 +312,7 @@ function deletePaste($pasteid) if (!is_dir($storagedir)) mkdir($storagedir,$mode=0705,$recursive=true); if (is_file($storagedir.$dataid)) // Oups... improbable collision. { - echo json_encode(array('status'=>1,'message'=>'You are unlucky. Try again.')); + echo json_encode(array('status'=>1,'message'=>translate('You are unlucky. Try again.'))); exit; } // New paste @@ -304,13 +327,15 @@ function deletePaste($pasteid) exit; } -echo json_encode(array('status'=>1,'message'=>'Server error.')); +echo json_encode(array('status'=>1,'message'=>translate('Server error.'))); exit; } + /* Process a paste deletion request. Returns an array ('',$ERRORMESSAGE,$STATUS) */ + function processPasteDelete($pasteid,$deletetoken) { if (preg_match('/\A[a-f\d]{16}\z/',$pasteid)) // Is this a valid paste identifier ? @@ -318,22 +343,23 @@ function processPasteDelete($pasteid,$deletetoken) $filename = dataid2path($pasteid).$pasteid; if (!is_file($filename)) // Check that paste exists. { - return array('','Paste does not exist, has expired or has been deleted.',''); + return array('',translate('Paste does not exist, has expired or has been deleted.'),''); } } else { - return array('','Invalid data',''); + return array('',translate('Invalid data'),''); } if (!slow_equals($deletetoken, hash_hmac('sha1', $pasteid , getServerSalt()))) // Make sure token is valid. { - return array('','Wrong deletion token. Paste was not deleted.',''); + return array('',translate('Wrong deletion token. Paste was not deleted.'),''); } // Paste exists and deletion token is valid: Delete the paste. deletePaste($pasteid); - return array('','','Paste was properly deleted.'); + //return array('','','Paste was properly deleted.'); + return array('','',translate('Paste was properly deleted.')); } /* Process a paste fetch request. @@ -346,12 +372,12 @@ function processPasteFetch($pasteid) $filename = dataid2path($pasteid).$pasteid; if (!is_file($filename)) // Check that paste exists. { - return array('','Paste does not exist, has expired or has been deleted.',''); + return array('',translate('Paste does not exist, has expired or has been deleted.'),''); } } else { - return array('','Invalid data',''); + return array('',translate('Invalid data'),''); } // Get the paste itself. @@ -361,7 +387,7 @@ function processPasteFetch($pasteid) if (isset($paste->meta->expire_date) && $paste->meta->expire_dateassign('VERSION',$VERSION); $page->assign('ERRORMESSAGE',$ERRORMESSAGE); $page->assign('STATUS',$STATUS); + +$page->assign('lang_file',$js_lang_file); + $page->draw('page'); ?> diff --git a/js/zerobin.js b/js/zerobin.js index 2b2497ff..4a811af3 100644 --- a/js/zerobin.js +++ b/js/zerobin.js @@ -5,6 +5,11 @@ * @author sebsauvage */ +function translate(msg) { + if (typeof(lang) == "object" && typeof(lang[msg]) == "string") return lang[msg]; + return msg; +} + // Immediately start random number generator collector. sjcl.random.startCollectors(); @@ -16,12 +21,15 @@ sjcl.random.startCollectors(); */ function secondsToHuman(seconds) { - if (seconds<60) { var v=Math.floor(seconds); return v+' second'+((v>1)?'s':''); } - if (seconds<60*60) { var v=Math.floor(seconds/60); return v+' minute'+((v>1)?'s':''); } - if (seconds<60*60*24) { var v=Math.floor(seconds/(60*60)); return v+' hour'+((v>1)?'s':''); } + //FIXME add optionnal s at the end of time word according to the language + //set two version plural et singular and set a flag for the use of one or another + if (seconds<60) { var v=Math.floor(seconds); return v+' '+translate('second')+((v>1)?'s':''); } + if (seconds<60*60) { var v=Math.floor(seconds/60); return v+' '+translate('minute')+((v>1)?'s':''); } + if (seconds<60*60*24) { var v=Math.floor(seconds/(60*60)); return v+' '+translate('hour')+((v>1)?'s':''); } // If less than 2 months, display in days: - if (seconds<60*60*24*60) { var v=Math.floor(seconds/(60*60*24)); return v+' day'+((v>1)?'s':''); } - var v=Math.floor(seconds/(60*60*24*30)); return v+' month'+((v>1)?'s':''); + if (seconds<60*60*24*60) { var v=Math.floor(seconds/(60*60*24)); return v+' '+translate('day')+((v>1)?'s':''); } + //FIXME if french add exeption for month + var v=Math.floor(seconds/(60*60*24*30)); return v+' '+translate('month')+((v>1)?'s':''); } /** @@ -195,7 +203,7 @@ function displayMessages(key, comments) { } catch(err) { $('div#cleartext').hide(); $('button#clonebutton').hide(); - showError('Could not decrypt data (Wrong key ?)'); + showError(translate('Could not decrypt data (Wrong key ?)')); return; } setElementText($('div#cleartext'), cleartext); @@ -206,9 +214,9 @@ function displayMessages(key, comments) { if (comments[0].meta.syntaxcoloring) applySyntaxColoring(); // Display paste expiration. - if (comments[0].meta.expire_date) $('div#remainingtime').removeClass('foryoureyesonly').text('This document will expire in '+secondsToHuman(comments[0].meta.remaining_time)+'.').show(); + if (comments[0].meta.expire_date) $('div#remainingtime').removeClass('foryoureyesonly').text(translate('This document will expire in')+' '+secondsToHuman(comments[0].meta.remaining_time)+'.').show(); if (comments[0].meta.burnafterreading) { - $('div#remainingtime').addClass('foryoureyesonly').text('FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.').show(); + $('div#remainingtime').addClass('foryoureyesonly').text(translate('FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.')).show(); $('button#clonebutton').hide(); // Discourage cloning (as it can't really be prevented). } @@ -232,7 +240,7 @@ function displayMessages(key, comments) { } var divComment = $('
' + '
' - + '' + + '' + '
'); setElementText(divComment.find('div.commentdata'), cleartext); // Convert URLs to clickable links in comment. @@ -252,7 +260,7 @@ function displayMessages(key, comments) { place.append(divComment); } - $('div#comments').append('
'); + $('div#comments').append('
'); $('div#discussion').show(); } } @@ -265,9 +273,9 @@ function displayMessages(key, comments) { function open_reply(source, commentid) { $('div.reply').remove(); // Remove any other reply area. source.after('
' - + '' + + '' + '' - + '
' + + '
' + '
 
' + '
'); $('input#nickname').focus(function() { @@ -289,11 +297,11 @@ function send_comment(parentid) { return; } - showStatus('Sending comment...', spin=true); + showStatus(translate('Sending comment')+'...', spin=true); var cipherdata = zeroCipher(pageKey(), $('textarea#replymessage').val()); var ciphernickname = ''; var nick=$('input#nickname').val(); - if (nick != '' && nick != 'Optional nickname...') { + if (nick != '' && nick != translate('Optional nickname')+'...') { ciphernickname = zeroCipher(pageKey(), nick); } var data_to_send = { data:cipherdata, @@ -304,18 +312,18 @@ function send_comment(parentid) { $.post(scriptLocation(), data_to_send, 'json') .error(function() { - showError('Comment could not be sent (serveur error or not responding).'); + showError(translate('Comment could not be sent (serveur error or not responding).')); }) .success(function(data) { if (data.status == 0) { - showStatus('Comment posted.'); + showStatus(translate('Comment posted.')); location.reload(); } else if (data.status==1) { - showError('Could not post comment: '+data.message); + showError(translate('Could not post comment')+': '+data.message); } else { - showError('Could not post comment.'); + showError(translate('Could not post comment')+'.'); } }); } @@ -333,12 +341,12 @@ function send_data() { // If sjcl has not collected enough entropy yet, display a message. if (!sjcl.random.isReady()) { - showStatus('Sending paste (Please move your mouse for more entropy)...', spin=true); + showStatus(translate('Sending paste (Please move your mouse for more entropy)'+'...'), spin=true); sjcl.random.addEventListener('seeded', function(){ send_data(); }); return; } - showStatus('Sending paste...', spin=true); + showStatus(translate('Sending paste'+'...'), spin=true); var randomkey = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0); var cipherdata = zeroCipher(randomkey, $('textarea#message').val()); @@ -350,7 +358,7 @@ function send_data() { }; $.post(scriptLocation(), data_to_send, 'json') .error(function() { - showError('Data could not be sent (serveur error or not responding).'); + showError(translate('Data could not be sent (serveur error or not responding)')+'.'); }) .success(function(data) { if (data.status == 0) { @@ -359,8 +367,8 @@ function send_data() { var deleteUrl = scriptLocation() + "?pasteid=" + data.id + '&deletetoken=' + data.deletetoken; showStatus(''); - $('div#pastelink').html('Your paste is ' + url + ' (Hit CTRL+C to copy)'); - $('div#deletelink').html('Delete link'); + $('div#pastelink').html(translate('Your paste is')+' ' + url + ' ('+translate('Hit CTRL+C to copy')+')'); + $('div#deletelink').html(''+translate('Delete link')+''); $('div#pasteresult').show(); selectText('pasteurl'); // We pre-select the link so that the user only has to CTRL+C the link. @@ -373,10 +381,10 @@ function send_data() { showStatus(''); } else if (data.status==1) { - showError('Could not create paste: '+data.message); + showError(translate('Could not create paste')+': '+data.message); } else { - showError('Could not create paste.'); + showError(translate('Could not create paste')+'.'); } }); } @@ -486,6 +494,7 @@ function newPaste() { * (We use the same function for paste and reply to comments) */ function showError(message) { + message=translate(message); $('div#status').addClass('errorMessage').text(message); $('div#replystatus').addClass('errorMessage').text(message); } @@ -585,7 +594,7 @@ $(function() { if ($('div#cipherdata').text().length > 1) { // Missing decryption key in URL ? if (window.location.hash.length == 0) { - showError('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL ?)'); + showError(translate('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL ?)')); return; } diff --git a/lang/fr.js b/lang/fr.js new file mode 100644 index 00000000..c7387efc --- /dev/null +++ b/lang/fr.js @@ -0,0 +1,26 @@ +lang={}; + +lang["second"]="seconde"; +lang["minute"]="minute"; +lang["hour"]="heure"; +lang["day"]="jour"; +lang["month"]="mois"; +lang["Could not decrypt data (Wrong key ?)"]="Impossible de déchiffrer les données (Mauvaise clé ?)"; +lang["This document will expire in"]="Ce document expirera dans"; +lang["FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again."]="POUR VOS YEUX SEULEMENT. Ne fermez pas cette fenêtre, ce message ne pourra être ré-affiché"; +lang["Add comment"]="Ajouter un commentaire"; +lang["Optional nickname"]="Pseudo optionnel"; +lang["Post comment"]="Poster le commentaire"; +lang["Delete link"]="Supprimer l'accès à ce lien"; +lang["Your paste is"]="votre texte est accessible via ce lien"; +lang["Hit CTRL+C to copy"]="Appuyez sur CTRL+C pour copier le lien"; +lang["Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL ?)"]="Impossible de déchiffrer le texte: La clé de déchiffrement manque dans l'URL (Avez vous utilisez une redirection ou un URL raccourcie qui retire certaine partie de l'URL ?)"; +lang["Could not create paste"]="Impossible de poster le texte"; +lang["Data could not be sent (serveur error or not responding)"]="Les données n'ont pu être envoyées (erreur serveur ou ne répond pas)"; +lang["Sending paste"]="Envoi du texte"; +lang["Sending paste (Please move your mouse for more entropy)"]="Envoi de texte (Bougez votre souris afin de générer de l'entropie"; +lang["Comment could not be sent (serveur error or not responding)."]="Le commentaire n'a pu être envoyé (erreur serveur ou ne répond pas"; +lang["Comment posted."]="Commentaire posté."; +lang["Could not post comment"]="Le commentaire n'a pu être posté"; +lang["Reply"]="Répondre"; +lang["Sending comment"]="Envoi du commentaire"; diff --git a/lang/fr.php b/lang/fr.php new file mode 100644 index 00000000..2d365736 --- /dev/null +++ b/lang/fr.php @@ -0,0 +1,42 @@ +in the browser using 256 bits AES."]="Les données sont chiffrées/déchiffrées par le navigateur en utilisant AES 256 bits."; + +$lang['More information on the']="Plus d'information sur le"; +$lang["project page"]="site du projet"; +$lang["Note: This is a test service:"]="Note: Il s'agit d'un service de test :"; +$lang["Data may be deleted anytime. Kittens will die if you abuse this service."]="Les données peuvent être supprimées à tout moment. Des chatons mourront si vous abusez de ce service"; +$lang["Because ignorance is bliss"]="Parce que l'ignorance est une bénédiction"; +$lang["Javascript is required for ZeroBin to work.
Sorry for the inconvenience."]="Javascript est requis pour le fonctionnement de ZeroBin.
Excusez nous pour la gêne occassionée"; +$lang["ZeroBin requires a modern browser to work."]="ZeroBin a besoin d'un navigateur moderne pour fonctionner."; +$lang["Still using Internet Explorer ?"]="Vous utilisez toujours Internet Explorer ?"; +$lang["Do yourself a favor, switch to a modern browser"]="Rendez vous un service, passez à un navigateur moderne"; +$lang["New"]="Nouveau"; +$lang["Send"]="Envoyer"; +$lang["Clone"]="Clone"; +$lang["Raw text"]="Texte brut"; +$lang["Expires"]="Expire"; +$lang["minutes"]="minutes"; +$lang["hour"]="heures"; +$lang["day"]="jour"; +$lang["week"]="semaine"; +$lang["month"]="mois"; +$lang["year"]="an"; +$lang["Never"]="Jamais"; +$lang["Burn after reading"]="Brûler après lecture"; +$lang["Open discussion"]="Ouvrir les commentaires"; +$lang["Syntax coloring"]="Coloration syntaxique"; +$lang["Discussion"]="Discussion"; +$lang["Paste was properly deleted."]="Le texte a été correctement supprimé"; +$lang["Please wait 10 seconds between each post."]="Patientez 10 secondes entre chaque post"; +$lang["Paste is limited to 2 Mb of encrypted data."]="Les textes sont limités à 2 Mb de données chiffée."; +$lang["Invalid data."]="Données invalides."; +$lang["You are unlucky. Try again."]="Vous n'avez pas de chance. Essayez encore."; +$lang["Server error."]="Erreur serveur."; +$lang["Paste does not exist, has expired or has been deleted."]="Le texte n'existe plus, il a expiré ou a été supprimé."; +$lang["Wrong deletion token. Paste was not deleted."]="Mauvais jeton de suppression. Le texte n'a pas été supprimé"; diff --git a/tpl/page.html b/tpl/page.html index 5499847f..ec696f4f 100644 --- a/tpl/page.html +++ b/tpl/page.html @@ -8,6 +8,7 @@ +{if condition="$lang_file!=''"}{/if} @@ -23,18 +24,18 @@
- ZeroBin is a minimalist, opensource online pastebin where the server has zero knowledge of pasted data. - Data is encrypted/decrypted in the browser using 256 bits AES. - More information on the project page.
- Note: This is a test service: - Data may be deleted anytime. Kittens will die if you abuse this service. + {"ZeroBin is a minimalist, opensource online pastebin where the server has zero knowledge of pasted data."|translate} + {"Data is encrypted/decrypted in the browser using 256 bits AES."|translate} + {"More information on the"|translate} {"project page"|translate}.
+ {"Note: This is a test service:"|translate} + {"Data may be deleted anytime. Kittens will die if you abuse this service."|translate}

ZeroBin


-

Because ignorance is bliss


+

{"Because ignorance is bliss"|translate}


{$VERSION}

- -
ZeroBin requires a modern browser to work.
-
Still using Internet Explorer ?  Do yourself a favor, switch to a modern browser: + +
{"ZeroBin requires a modern browser to work."|translate}
+
{"Still using Internet Explorer ?"|translate}  {"Do yourself a favor, switch to a modern browser"|translate}: Firefox, Opera, Chrome, @@ -43,34 +44,34 @@

{$VERSION}

{$STATUS}
- - - - -