diff --git a/src/core/i18n.js b/src/core/i18n.js new file mode 100644 index 0000000..cf20818 --- /dev/null +++ b/src/core/i18n.js @@ -0,0 +1,41 @@ +import path from "path" +import fs from "fs" + +const _defaultLocale = 'fr' +const _localePath = path.dirname(process.argv[1]) + '/locales' +const _locales = { + default: null +} + +const init = () => { + _locales[_defaultLocale] = JSON.parse(fs.readFileSync(_localePath + '/' + _defaultLocale + '.json')) + _locales.default = _locales[_defaultLocale] +} + +if(! _locales.default) init() + +const capitalize = (string) => { + return ( string && String(string[0]).toUpperCase() + String(string).slice(1)) || "" +} +const getLocaleData = (locale) => { + if(! locale) locale = _defaultLocale + if(! _locales[locale]) { + if(! fs.existsSync(_localePath + '/' + locale + '.json')) { + return _locales.default + } + _locales[locale] = JSON.parse(fs.readFileSync(_localePath + '/' + locale + '.json')) + } + return _locales[locale] +} + +const getString = (key, locale) => { + const localeData = getLocaleData(locale) + if(localeData.strings[key]) return localeData.strings[key] + else if(_locales.default.strings[key]) return _locales.default.strings[key] + return key +} + +export default { + capitalize, + getString, +} \ No newline at end of file diff --git a/src/core/server.js b/src/core/server.js index c36b065..129d8f0 100644 --- a/src/core/server.js +++ b/src/core/server.js @@ -2,6 +2,7 @@ import fs from "fs" import express from "express" import http from "http" import https from "https" +import i18n from "./i18n.js" import routes from "./routes.js" const defaulthandler = (req, res, next) => { @@ -27,6 +28,8 @@ const start = (srvConfig) => { router.use(express.json()) router.pug = pug + // router.i18n = i18n + app.locals.i18n = i18n routes.load(router, srvConfig.features) diff --git a/src/core/vault.js b/src/core/vault.js index ff4d38b..2f81d90 100644 --- a/src/core/vault.js +++ b/src/core/vault.js @@ -2,6 +2,7 @@ import fs from 'fs' import cron from 'node-cron' import crypto from 'crypto' import config from "./config.js" +import i18n from "./i18n.js" import mailer from './mailer.js' const _config = config.get() @@ -76,12 +77,20 @@ const decrypt = (data) => { const emailReadNotify = (data) => { const email = { to: data.emailNotify, - subject: "Secret read", - text: 'Secret read' + subject: i18n.capitalize(i18n.getString('secret_read')), + text: i18n.capitalize(i18n.getString('secret_read')) } - if(data.subject) email.subject = email.subject + ' - ' + data.subject - if(data.message) email.text = data.message - if(data.senderName) email.text = email.text + '\n\n' + data.senderName + if(data.emailNotifySubject) email.subject = email.subject + ': ' + data.emailNotifySubject + else if(data.subject) email.subject = email.subject + ': ' + data.subject + if(data.emailNotifyMessage) { + if(data.message) { + email.text = data.emailNotifyMessage + email.text = email.text + '\n\n' + data.message + } else { + email.text = data.emailNotifyMessage + } + } else if(data.message) email.text = data.message + else email.text = email.subject mailer.send(email) } @@ -92,12 +101,15 @@ const createData = (data = { subject: null, message: null, secret: null, - emailNotify: null, expireDays: null, expireHours: null, expireTime: null, maxReads: null, - emailOTL: null, + showMethod: null, + showMethodEMail: null, + emailNotify: null, + emailNotifySubject: null, + emailNotifyMessage: null, }) => { if(! data) return null const validatedData = {} @@ -105,14 +117,28 @@ const createData = (data = { if(data.subject && data.subject != "") validatedData.subject = data.subject if(data.message && data.message != "") validatedData.message = data.message if(data.secret && data.secret != "") validatedData.secret = data.secret - if(data.emailNotify && data.emailNotify != "") validatedData.emailNotify = data.emailNotify - if(data.emailOTL && data.emailOTL != "") validatedData.emailOTL = data.emailOTL if(data.maxReads && data.maxReads != "") validatedData.maxReads = data.maxReads let expireTime = 0 if(data.expireDays && data.expireDays > 0) expireTime = +data.expireDays * 24 * 60 if(data.expireHours && data.expireHours > 0) expireTime = expireTime + +data.expireHours * 60 if(data.expireTime && data.expireTime > 0) expireTime = +data.expireTime if(expireTime > 0) validatedData.expireTime = expireTime + switch(data.showMethod) { + case 'email': + if(data.showMethodEMail && data.showMethodEMail != '') { + validatedData.showMethod = data.showMethod + validatedData.showMethodEMail = data.showMethodEMail + } else { + validatedData.showMethod = 'link' + } + break + default: + validatedData.showMethod = 'link' + } + if(data.showEMmail && data.showEMmail != "") validatedData.showEMmail = data.showEMmail + if(data.emailNotify && data.emailNotify != "") validatedData.emailNotify = data.emailNotify + if(data.emailNotifySubject && data.emailNotifySubject != "") validatedData.emailNotifySubject = data.emailNotifySubject + if(data.emailNotifyMessage && data.emailNotifyMessage != "") validatedData.emailNotifyMessage = data.emailNotifyMessage if(! validatedData.secret || validatedData.secret === '') return null if(! validatedData.expireTime) validatedData.expireTime = 24 * 60 diff --git a/src/html/style.css b/src/html/style.css index 16e9236..b0b954d 100644 --- a/src/html/style.css +++ b/src/html/style.css @@ -10,6 +10,13 @@ body { margin: 0; color: #e3d1c7; } +h1::first-letter { + text-transform: capitalize; +} +table { + empty-cells: show; + border-collapse: collapse; +} input { border: 1px solid transparent; } @@ -45,6 +52,9 @@ input:invalid, textarea:invalid { .monospace { font-family: 'Courier New', Courier, monospace; } +.capitalize::first-letter { + text-transform: capitalize; +} .form { max-width: 800px; @@ -70,6 +80,9 @@ input:invalid, textarea:invalid { margin-left: 4px; margin-bottom: 2px; } +.titlebox::first-letter { + text-transform: capitalize; +} .textbox { border: none; diff --git a/src/locales/fr.json b/src/locales/fr.json new file mode 100644 index 0000000..06d4b93 --- /dev/null +++ b/src/locales/fr.json @@ -0,0 +1,24 @@ +{ + "strings": { + "optional": "optionnel", + "email": "e-mail", + "share": "partager", + "newlink": "nouveau lien", + "sender_name": "expéditeur", + "subject": "sujet", + "message": "message", + "secret": "secret", + "secret_sample": "votre secret", + "expire": "expiration", + "day_s": "jour(s)", + "hour_s": "heure(s)", + "show_s": "affichage(s)", + "show_method": "méthode d'affichage", + "show_method_link": "lien direct", + "show_method_link_and_click": "lien direct avec action", + "show_method_one_time_link_by_email": "lien unique par e-mail", + "notification": "notification", + "create_new_link": "créer le nouveau lien", + "secret_read": "secret lu" + } +} \ No newline at end of file diff --git a/src/pug/create.pug b/src/pug/create.pug index 6c20a80..b32323a 100644 --- a/src/pug/create.pug +++ b/src/pug/create.pug @@ -22,11 +22,21 @@ block script if(Subject.value != '') data.subject = Subject.value if(Message.value != '') data.message = Message.value if(Secret.value != '') data.secret = Secret.value - if(EMailNotify.value != '') data.emailNotify = EMailNotify.value data.expireDays = ExpireDays.value data.expireHours = ExpireHours.value data.maxReads = MaxReads.value - if(EMailOTL.value != '') data.emailOTL = EMailOTL.value + data.showMethod = 'link' + if(ShowMethodEMail.checked) { + if(ShowMethodEMailValue.value != '') { + data.showMethod = 'email' + data.showMethodEMail = ShowMethodEMailValue.value + } + } + if(document.getElementById('Notification').checked) { + if(EMailNotify.value != '') data.emailNotify = EMailNotify.value + if(EMailNotifySubject.value != '') data.emailNotifySubject = EMailNotifySubject.value + if(EMailNotifyMessage.value != '') data.emailNotifyMessage = EMailNotifyMessage.value + } const path = window.location.pathname fetch(path, { method: "post", @@ -41,46 +51,80 @@ block script }) }) } + const showMethodChanged = () => { + if(document.getElementById('ShowMethodLink').checked) { + ShowMethodEMailValue.disabled = true + ShowMethodEMailValue.required = false + } else { + ShowMethodEMailValue.disabled = false + ShowMethodEMailValue.required = true + } + } + const notificationChanged = () => { + if(document.getElementById('Notification').checked) { + document.getElementById('NotificationOptions').style.display = '' + document.getElementById('EMailNotify').required = true + } else { + document.getElementById('NotificationOptions').style.display = 'none' + document.getElementById('EMailNotify').required = false + } + } block content div.center div.form - h1 Nouveau lien + h1 #{i18n.getString('newlink')} div.panel.left - div.titlebox Expéditeur + div.titlebox #{i18n.getString('sender_name')} div - input#SenderName(type="text", placeholder="(Optionel)").textbox.fullwidth + input#SenderName(type="text", placeholder=i18n.getString('optional')).textbox.fullwidth div.panel.left - div.titlebox Sujet + div.titlebox #{i18n.getString('subject')} div - input#Subject(type="text", placeholder="(Optionel)").textbox.fullwidth + input#Subject(type="text", placeholder=i18n.getString('optional')).textbox.fullwidth div.panel.left - div.titlebox Message + div.titlebox #{i18n.getString('message')} div - textarea#Message(rows="3", placeholder="(Optionel)").messagebox.fullwidth + textarea#Message(rows="3", placeholder=i18n.getString('optional')).messagebox.fullwidth div.panel.left - div.titlebox Secret (*) + div.titlebox #{i18n.getString('secret')} (*) div - textarea#Secret(rows="4", placeholder="Votre secret", required).messagebox.fullwidth.monospace + textarea#Secret(rows="4", placeholder=i18n.getString('secret_sample'), required).messagebox.fullwidth.monospace div.panel.left - div.titlebox E-Mail (Notifier) - div - input#EMailNotify(type="email", placeholder="(Optionel) Votre e-mail pour être notifié").messagebox.fullwidth - div.panel.left - div.titlebox Expiration + div.titlebox #{i18n.getString('expire')} table.fullwidth tr td input#ExpireDays(type="number", value="2", min="0", max="13").textbox.small - span.inlineleftspace jour(s) + span.inlineleftspace #{i18n.getString('day_s')} input#ExpireHours(type="number", value="1", min="1", max="23").textbox.small.inlineleftspace - span.inlineleftspace heure(s) + span.inlineleftspace #{i18n.getString('hour_s')} td.right input#MaxReads(type="number", value="1", min="0", max="999").textbox.small.inlineleftspace - span.inlineleftspace affichage(s) + span.inlineleftspace #{i18n.getString('show_s')} div.panel.left - div.titlebox E-Mail (OTL) + div.titlebox #{i18n.getString('show_method')} div - input#EMailOTL(type="email", placeholder="(Optionel) E-mail du destinatire pour OTL").messagebox.fullwidth + input#ShowMethodLink(type="radio", name="show_method", value="link", onchange="showMethodChanged()", checked) + label(for="ShowMethodLink") #{i18n.getString('show_method_link')} + div + table.fullwidth + tr + td + input#ShowMethodEMail(type="radio", name="show_method", value="email", onchange="showMethodChanged()") + label(for="ShowMethodEMail") #{i18n.getString('show_method_one_time_link_by_email')} + td.right + input#ShowMethodEMailValue(type="email", disabled="true", placeholder=i18n.getString('email')).messagebox.fullwidth + div.panel.left + div.titlebox + span #{i18n.getString('notification')} + input#Notification(type="checkbox", onchange="notificationChanged()") + div#NotificationOptions(style="display: none;").panel.left + div.panel.left + input#EMailNotify(type="email", placeholder=placeholder=i18n.getString('email')).messagebox.fullwidth + div.panel.left + input#EMailNotifySubject(type="text", placeholder=placeholder=i18n.getString('subject')).messagebox.fullwidth + div.panel.left + textarea#EMailNotifyMessage(rows="3", placeholder=placeholder=i18n.getString('message')).messagebox.fullwidth div.panel.controlpanel - button(onclick="createLink()").button.fullwidth Créer le lien + button(onclick="createLink()").button.fullwidth.capitalize #{i18n.getString('share')}