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 @@