Explorar el Código

Merge pull request #5 from babolivier/development

Added translations
Brendan Abolivier hace 8 años
padre
commit
8834bb46c6
Se han modificado 7 ficheros con 131 adiciones y 47 borrados
  1. 11
    3
      README.md
  2. 58
    36
      front/form.js
  3. 20
    0
      locales/en.json
  4. 20
    0
      locales/fr.json
  5. 19
    6
      server.js
  6. 2
    1
      settings.example.json
  7. 1
    1
      template.pug

+ 11
- 3
README.md Ver fichero

@@ -78,15 +78,18 @@ First, you must rename the `settings.example.conf` into `settings.conf`, and edi
78 78
         "you@example.tld",
79 79
         "someone.else@example.com"
80 80
     ],
81
-    "formOrigin": "https://example.tld"
81
+    "formOrigin": "https://example.tld",
82
+    "language": "en"
82 83
 }
83 84
 ```
84 85
 
85 86
 The `mailserver` section is the set of parameters which will be passed to nodemailer's transporter initialisation, describing the output mail server and following the same structure as the `option` object in [nodemailer's SMTP configuration section](https://github.com/nodemailer/nodemailer#set-up-smtp). Please head there to have the full list of parameters.
86 87
 
87
-The `recipients` server is an array containing the e-mail addresses any message sent via the form will be sent to. Just write down the form's recipient(s)'s addresse(s).
88
+The `recipients` section is an array containing the e-mail addresses any message sent via the form will be sent to. Just write down the form's recipient(s)'s addresse(s).
88 89
 
89
-Finally, the `formOrigin` part is a string containing the origin of the page you'll include the contact form into. This allows SMAM to work with the [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) security most browser use. For more info on how to fill this field, and what is an origin, please give a look at [the MDN's definition](https://developer.mozilla.org/en-US/docs/Glossary/origin).
90
+The `formOrigin` part is a string containing the origin of the page you'll include the contact form into. This allows SMAM to work with the [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) security most browser use. For more info on how to fill this field, and what is an origin, please give a look at [the MDN's definition](https://developer.mozilla.org/en-US/docs/Glossary/origin).
91
+
92
+Finally, the `language` string tells SMAM in which language you want your form served. Possible values are all the files in `locales/`'s names (without the `.json`). To create your own translation, please read the section below.
90 93
 
91 94
 ## Templating
92 95
 
@@ -125,6 +128,11 @@ Now it's all yours to make good use of all these identifiers and have a magnific
125 128
 
126 129
 I think that the code in itself is clear enough, if not please tell me so I can detail everything here!
127 130
 
131
+## Translating
132
+
133
+Right now, SMAM is only available in French and English. If you want to implement your own language, you can do so by creating a new file in the `locales/` directory, named following your language's identifier with the `.json` extension (`en.json` for exemple). You can then have a look at the strings in `en.json`, copy them and translate them in your language. To use this translation, just set the `language` field (in your settings file) to your language's identifier.
134
+
135
+As I don't speak all languages, [pull requests](#contribute) with new languages are more than welcome! You'd be sharing your knowledge with the whole community and help more people using SMAM around the world :smile:
128 136
 
129 137
 ## Contribute
130 138
 

+ 58
- 36
front/form.js Ver fichero

@@ -6,16 +6,44 @@ var items = {
6 6
 };
7 7
 
8 8
 var server  = getServer();
9
-var xhrSend = new XMLHttpRequest();
10
-
11 9
 var token = "";
12
-var xhrToken = new XMLHttpRequest();
13
-xhrToken.onreadystatechange = function() {
14
-    if(xhrToken.readyState == XMLHttpRequest.DONE) {
15
-        token = xhrToken.responseText;
16
-    }
10
+var lang = {};
11
+
12
+var xhr = {
13
+    lang: new XMLHttpRequest(),
14
+    token: new XMLHttpRequest(),
15
+    send: new XMLHttpRequest()
17 16
 }
18 17
 
18
+// XHR callbacks
19
+
20
+xhr.token.onreadystatechange = function() {
21
+    if(xhr.token.readyState == XMLHttpRequest.DONE) {
22
+        token = xhr.token.responseText;
23
+    }
24
+};
25
+
26
+xhr.lang.onreadystatechange = function() {
27
+    if(xhr.lang.readyState == XMLHttpRequest.DONE) {
28
+        lang = JSON.parse(xhr.lang.responseText);
29
+    }
30
+};
31
+
32
+xhr.send.onreadystatechange = function() {
33
+    if(xhr.send.readyState == XMLHttpRequest.DONE) {
34
+        let status = document.getElementById('form_status');
35
+        status.setAttribute('class', '');
36
+        if(xhr.send.status === 200) {
37
+            cleanForm();
38
+            status.setAttribute('class', 'success');
39
+            status.innerHTML = lang.send_status_success;
40
+        } else {
41
+            status.setAttribute('class', 'failure');
42
+            status.innerHTML = lang.send_status_failure;
43
+        }
44
+    }
45
+};
46
+
19 47
 
20 48
 // Returns the server's base URI based on the user's script tag
21 49
 // return: the SMAM server's base URI
@@ -40,6 +68,9 @@ function getServer() {
40 68
 // id: HTML identifier of the document's block to create the form into
41 69
 // return: nothing
42 70
 function generateForm(id) {
71
+    // Get translated strings
72
+    getLangSync();
73
+    
43 74
     var el = document.getElementById(id);
44 75
     
45 76
     // Set the form's behaviour
@@ -51,10 +82,10 @@ function generateForm(id) {
51 82
     el.appendChild(status);
52 83
     
53 84
     var input = {
54
-        name: getField(items.name, 'Your name', false, 'input'), // TODO: configurable prefix
55
-        addr: getField(items.addr, 'Your e-mail address', true, 'input'),
56
-        subj: getField(items.subj, 'Your message\'s subject', false, 'input'),
57
-        text: getField(items.text, 'Your message', false, 'textarea')
85
+        name: getField(items.name, lang.form_name_label, false, 'input'),
86
+        addr: getField(items.addr, lang.form_addr_label, true, 'input'),
87
+        subj: getField(items.subj, lang.form_subj_label, false, 'input'),
88
+        text: getField(items.text, lang.form_mesg_label, false, 'textarea')
58 89
     };
59 90
     
60 91
     // Adding nodes to document
@@ -66,24 +97,7 @@ function generateForm(id) {
66 97
     
67 98
     // Adding submit button
68 99
     
69
-    el.appendChild(getSubmitButton('form_subm', 'Send the mail'));
70
-    
71
-    // Setting the XHR callback
72
-    
73
-    xhrSend.onreadystatechange = function() {
74
-        if(xhrSend.readyState == XMLHttpRequest.DONE) {
75
-            let status = document.getElementById('form_status');
76
-            status.setAttribute('class', '');
77
-            if(xhrSend.status === 200) {
78
-                cleanForm();
79
-                status.setAttribute('class', 'success');
80
-                status.innerHTML = 'Your message has been sent.';
81
-            } else {
82
-                status.setAttribute('class', 'failure');
83
-                status.innerHTML = 'An error happened while sending your message, please retry later.';
84
-            }
85
-        }
86
-    };
100
+    el.appendChild(getSubmitButton('form_subm', lang.form_subm_label));
87 101
     
88 102
     // Retrieve the token from the server
89 103
     
@@ -177,11 +191,11 @@ function sendForm() {
177 191
     // Clear status
178 192
     let status = document.getElementById('form_status');
179 193
     status.setAttribute('class', 'sending');
180
-    status.innerHTML = 'Sending the e-mail';
194
+    status.innerHTML = lang.send_status_progress;
181 195
     
182
-    xhrSend.open('POST', server + '/send');
183
-    xhrSend.setRequestHeader('Content-Type', 'application/json');
184
-    xhrSend.send(JSON.stringify(getFormData()));
196
+    xhr.send.open('POST', server + '/send');
197
+    xhr.send.setRequestHeader('Content-Type', 'application/json');
198
+    xhr.send.send(JSON.stringify(getFormData()));
185 199
     
186 200
     // Get a new token
187 201
     getToken();
@@ -211,9 +225,17 @@ function cleanForm() {
211 225
 }
212 226
 
213 227
 
214
-// Ask the server for a token
228
+// Asks the server for a token
215 229
 // return: nothing
216 230
 function getToken() {
217
-    xhrToken.open('GET', server + '/register');
218
-    xhrToken.send();
231
+    xhr.token.open('GET', server + '/register');
232
+    xhr.token.send();
233
+}
234
+
235
+
236
+// Asks the server for translated strings to display
237
+// return: notghing
238
+function getLangSync() {
239
+    xhr.lang.open('GET', server + '/lang', false);
240
+    xhr.lang.send();
219 241
 }

+ 20
- 0
locales/en.json Ver fichero

@@ -0,0 +1,20 @@
1
+{
2
+    "client": {
3
+        "form_name_label": "Your name",
4
+        "form_addr_label": "Your e-mail address",
5
+        "form_subj_label": "Your message's subject",
6
+        "form_mesg_label": "Your message",
7
+        "form_subm_label": "Send the mail",
8
+        "send_status_success": "Your message has been sent.",
9
+        "send_status_failure": "An error happened while sending your message, please retry later.",
10
+        "send_status_progress": "Sending the e-mail"
11
+    },
12
+    "server": {
13
+        "log_server_start": "Server started on",
14
+        "log_sending": "Sending message from",
15
+        "log_send_success": "Message sent to",
16
+        "log_send_failure": "Message failed to send to",
17
+        "log_invalid_token": "just tried to send a message with an invalid token",
18
+        "log_cleared_token": "Cleared expired tokens"
19
+    }
20
+}

+ 20
- 0
locales/fr.json Ver fichero

@@ -0,0 +1,20 @@
1
+{
2
+    "client": {
3
+        "form_name_label": "Votre nom",
4
+        "form_addr_label": "Votre adresse e-mail",
5
+        "form_subj_label": "Sujet de votre message",
6
+        "form_mesg_label": "Votre message",
7
+        "form_subm_label": "Envoyer",
8
+        "send_status_success": "Votre message a été envoyé.",
9
+        "send_status_failure": "Une erreur est survenue lors de l'envoi du message, merci de réessayer plus tard.",
10
+        "send_status_progress": "Envoi du message en cours"
11
+    },
12
+    "server": {
13
+        "log_server_start": "Serveur démarré pour",
14
+        "log_sending": "Envoi d'un message de",
15
+        "log_send_success": "Message envoyé à",
16
+        "log_send_failure": "Erreur lors de l'envoi du message à",
17
+        "log_invalid_token": "vient d'essayer d'envoyer un message avec un jeton invalide",
18
+        "log_cleared_token": "Les jetons expirés ont été effacés"
19
+    }
20
+}

+ 19
- 6
server.js Ver fichero

@@ -3,6 +3,10 @@ var nodemailer  = require('nodemailer');
3 3
 var crypto      = require('crypto');
4 4
 var settings    = require('./settings');
5 5
 
6
+// Translation
7
+var locale  = require('./locales/' + settings.language);
8
+var lang    = locale.server;
9
+
6 10
 // Web server
7 11
 var bodyParser  = require('body-parser');
8 12
 var cors        = require('cors');
@@ -98,7 +102,7 @@ app.post('/send', function(req, res, next) {
98 102
     // text entered by the user
99 103
     params.html = pug.renderFile('template.pug', params);
100 104
     
101
-    log.info('Sending message from ' + params.replyTo);
105
+    log.info(lang.log_sending, params.replyTo);
102 106
     
103 107
     // Send the email to all users
104 108
     sendMails(params, function(err, infos) {
@@ -116,13 +120,22 @@ app.post('/send', function(req, res, next) {
116 120
 });
117 121
 
118 122
 
123
+// A request on /lang sends translated strings (according to the locale set in
124
+// the app settings)
125
+app.get('/lang', function(req, res, next) {
126
+    // Response will be JSON
127
+    res.header('Access-Control-Allow-Headers', 'Content-Type');
128
+    res.status(200).send(locale.client);
129
+});
130
+
131
+
119 132
 // Use either the default port or the one chosen by the user (PORT env variable)
120 133
 var port = process.env.PORT || 1970;
121 134
 // Same for the host (using the HOST env variable)
122 135
 var host = process.env.HOST || '0.0.0.0';
123 136
 // Start the server
124 137
 app.listen(port, host, function() {
125
-    log.info('Server started on ' + host + ':' + port);
138
+    log.info(lang.log_server_start, host + ':' + port);
126 139
 });
127 140
 
128 141
 
@@ -166,11 +179,11 @@ function sendMails(params, update, done) {
166 179
 // return: nothing
167 180
 function logStatus(infos) {
168 181
     if(infos.accepted.length !== 0) {
169
-        log.info('Message sent to ' + infos.accepted[0]);
182
+        log.info(lang.log_send_success, infos.accepted[0]);
170 183
     }
171 184
     if(infos.rejected.length !== 0) {
172 185
         status.failed++;
173
-        log.info('Message failed to send to ' + infos.rejected[0]);
186
+        log.info(lang.log_send_failure, infos.rejected[0]);
174 187
     }
175 188
 }
176 189
 
@@ -199,7 +212,7 @@ function checkToken(ip, token) {
199 212
     }
200 213
     
201 214
     if(!verified) {
202
-        log.warn(ip + ' just tried to send a message with an invalid token');
215
+        log.warn(ip, lang.log_invalid_token);
203 216
     }
204 217
     
205 218
     return verified;
@@ -239,5 +252,5 @@ function cleanTokens() {
239 252
         }
240 253
     }
241 254
     
242
-    log.info('Cleared expired tokens');
255
+    log.info(lang.log_cleared_token);
243 256
 }

+ 2
- 1
settings.example.json Ver fichero

@@ -13,5 +13,6 @@
13 13
         "you@example.tld",
14 14
         "someone.else@example.com"
15 15
     ],
16
-    "formOrigin": "https://example.tld"
16
+    "formOrigin": "https://example.tld",
17
+    "language": "en"
17 18
 }

+ 1
- 1
template.pug Ver fichero

@@ -5,6 +5,6 @@ html
5 5
             span= subject
6 6
         p.from
7 7
             span(style="font-weight:bold") Sent from: 
8
-            span= from
8
+            span= replyTo
9 9
         
10 10
         p= html