diff --git a/functions/i18next.config.ts b/functions/i18next.config.ts
new file mode 100644
index 0000000..2407823
--- /dev/null
+++ b/functions/i18next.config.ts
@@ -0,0 +1,29 @@
+import {InitOptions} from "i18next";
+// import all namespaces (for the default language, only)
+import emailEn from "../public/locales/en/email.json";
+import emailFr from "../public/locales/fr/email.json";
+import resourceEn from "../public/locales/en/resource.json";
+import resourceFr from "../public/locales/fr/resource.json";
+
+
+export const defaultNS = "email";
+
+export const resources = {
+ en: {
+ email: emailEn,
+ resource: resourceEn,
+ },
+ fr: {
+ email: emailFr,
+ resource: resourceFr,
+ },
+} as const;
+
+
+export const i18n: InitOptions = {
+ // https://www.i18next.com/overview/configuration-options#logging
+ debug: process.env.NODE_ENV === 'development',
+ ns: ["resource", "email"],
+ resources,
+ defaultNS: defaultNS,
+}
diff --git a/functions/send-emails/invite-fr.html b/functions/send-emails/admin.html
similarity index 70%
rename from functions/send-emails/invite-fr.html
rename to functions/send-emails/admin.html
index d0f614b..07b2fbb 100644
--- a/functions/send-emails/invite-fr.html
+++ b/functions/send-emails/admin.html
@@ -70,7 +70,9 @@
- Nous sommes très heureux de vous partager ce lien de vote ! Vous allez pouvoir voter avec le jugement majoritaire.
+
+ {{#i18n 'email.admin.happy' }}{{/i18n}}
+
@@ -79,7 +81,7 @@
-
+
|
@@ -92,7 +94,7 @@
- Bonjour ! 🙂
+ {{#i18n 'email.hello'}}Hi, there! 🙂{{/i18n}}
|
@@ -105,39 +107,18 @@
- Nous sommes très heureux de vous partager ce lien de vote ! Vous allez pouvoir voter avec le jugement majoritaire.
+
+ {{#i18n 'email.admin.happy'}}{{/i18n}}
+
|
-
-
- Vous avez été invité·e à participer à l'élection suivante :
- |
-
-
-
-
-
- |
-
-
- Si le lien ne fonctionne pas, vous pouvez le copier et le coller dans la barre de navigation de votre navigateur.
+ {{#i18n 'email.admin.why'}}{{/i18n}}
- %recipient.urlVote%
+ %recipient.title%
|
@@ -145,16 +126,16 @@
- A la fin de l'élection, vous pourrez accéder aux résultats en cliquant sur ce lien :
-
- %recipient.urlResult%
+ {{#i18n 'email.admin.linkAdmin' }}{{/i18n}}
+
+ %recipient.urlAdmin%
|
- Bon vote, Mieux Voter
+ {{#i18n 'email.bye'}}{{/i18n}}, {{#i18n 'common.better-vote'}}{{/i18n}}
|
@@ -168,10 +149,14 @@
- Besoin de plus d'information
+
+ {{#i18n 'email.about-mj'}}{{/i18n}}
+
- Vous souhaitez nous aider ?
+
+ {{#i18n 'common.support-us'}}{{/i18n}}
+
|
@@ -186,13 +171,15 @@
- Vous avez été invité·e à participer à l'élection suivante
+
+ {{#i18n email.why }}{{/i18n}}
+
|
- Mieux Voter - app@mieuxvoter.fr
+ {{#i18n common.better-vote }}{{/i18n}} - {{ from_email_address }}
|
diff --git a/functions/send-emails/admin.txt b/functions/send-emails/admin.txt
new file mode 100644
index 0000000..86fc8bb
--- /dev/null
+++ b/functions/send-emails/admin.txt
@@ -0,0 +1,15 @@
+{{#i18n 'email.hello'}}{{/i18n}}
+
+{{#i18n 'email.admin.happy'}}{{/i18n}}
+
+{{#i18n 'email.admin.why'}}{{/i18n}}
+
+%recipient.title%
+
+{{#i18n 'email.admin.linkAdmin' }}{{/i18n}}
+
+%recipient.urlAdmin%
+
+{{#i18n 'email.bye'}}{{/i18n}}
+
+{{#i18n 'common.better-vote'}}{{/i18n}}
diff --git a/functions/send-emails/index.ts b/functions/send-emails/index.ts
index a69f9b3..416dc39 100644
--- a/functions/send-emails/index.ts
+++ b/functions/send-emails/index.ts
@@ -3,9 +3,9 @@ import {Handler} from "@netlify/functions";
import formData from 'form-data';
import Mailgun from 'mailgun.js';
import Handlebars from 'handlebars';
-import {i18n} from '../../next-i18next.config.js';
+import {i18n} from '../i18next.config';
import i18next from 'i18next';
-import {MailgunMessageData} from "mailgun.js/interfaces/Messages.js";
+import {MailgunMessageData, MessagesSendResult} from "mailgun.js/interfaces/Messages.js";
const {
@@ -15,6 +15,7 @@ const {
FROM_EMAIL_ADDRESS,
REPLY_TO_EMAIL_ADDRESS,
} = process.env;
+console.log("MAILGUN URL", MAILGUN_URL)
const mailgun = new Mailgun(formData);
const mg = mailgun.client({
@@ -23,15 +24,9 @@ const mg = mailgun.client({
url: MAILGUN_URL
});
-const txtStr = fs.readFileSync(__dirname + "/invite.txt").toString()
-
-i18next.init({
- fallbackLng: 'en',
- ns: ['file1', 'file2'],
- defaultNS: 'file1',
- debug: true
-}, (err, t) => {
+console.log("I18N config", i18n)
+i18next.init(i18n, (err, t) => {
if (err) return console.log('something went wrong loading', err);
t("foo");
});
@@ -39,6 +34,8 @@ i18next.init({
Handlebars.registerHelper('i18n',
(str: string): string => {
+ console.log("I18N", str)
+ console.log("I18Next", i18next, i18next.t)
return (i18next != undefined ? i18next.t(str) : str);
}
);
@@ -46,7 +43,6 @@ Handlebars.registerHelper('i18n',
interface RequestPayload {
recipients: {[email: string]: {[key: string]: string}};
- options: any;
locale: string;
action: "invite" | "admin";
}
@@ -55,6 +51,7 @@ const handler: Handler = async (event) => {
/**
* Send a mail using Mailgun
*/
+
if (event.httpMethod !== 'POST') {
return {
statusCode: 405,
@@ -63,7 +60,7 @@ const handler: Handler = async (event) => {
};
}
- const {recipients, options, action, locale} = JSON.parse(event.body) as RequestPayload;
+ const {recipients, action, locale} = JSON.parse(event.body) as RequestPayload;
if (!recipients) {
return {
@@ -79,49 +76,72 @@ const handler: Handler = async (event) => {
};
}
- if (!locale || !["fr", "gb"].includes(locale)) {
+ if (!locale || !["fr", "en"].includes(locale)) {
return {
statusCode: 422,
body: 'Unknown locale.',
};
}
- // TODO setup locale
+ const err = await i18next.changeLanguage(locale, (err, t) => {
+
+ if (err) return {"error": err}
+ });
+ if (err && err["error"]) {
+ return {statusCode: 200, ...err["error"]}
+ }
- const htmlTemplate = "FOO"; //fs.readFileSync(`${__dirname}/${action}.txt`).toString();
- const htmlContent = Handlebars.compile(htmlTemplate);
+ const templates = ["txt", "html"].map(ext =>
+ fs.readFileSync(`${__dirname}/${action}.${ext}`).toString());
+ const contents = templates.map(tpl => Handlebars.compile(tpl)({from_email_address: FROM_EMAIL_ADDRESS}));
const payload: MailgunMessageData = {
- // from: `${i18next.t("Mieux Voter")} `,
+ // from: `${i18next.t("Mieux Voter")} `,
from: FROM_EMAIL_ADDRESS || '"Mieux Voter" ',
to: Object.keys(recipients),
- subject: i18next.t(`emails.subject-${action}`),
- html: htmlContent({}),
+ subject: i18next.t(`email.${action}.subject`),
+ txt: contents[0],
+ html: contents[1],
'h:Reply-To': REPLY_TO_EMAIL_ADDRESS || 'app@mieuxvoter.fr',
'o:tag': action,
'o:require-tls': true,
'o:dkim': true,
'recipient-variables': JSON.stringify(recipients),
};
- console.log(payload)
try {
- const res = await mg.messages.create(MAILGUN_DOMAIN, payload)
+ const res: MessagesSendResult = await mg.messages.create(MAILGUN_DOMAIN, payload)
+
+ if (res.status != 200) {
+ return {
+ statusCode: res.status,
+ body: JSON.stringify(
+ {
+ "message": res.message,
+ "details": res.details,
+ }
+ )
+ }
+
+ }
return {
statusCode: 200,
body: JSON.stringify(
{
- ...res,
- "status": `${recipients.length} emails were sent.`,
+ "message": res.message,
+ "details": res.details,
+ "status": "200",
+ "results": `${Object.keys(recipients).length} emails were sent.`,
}
)
}
- } catch {
+ } catch (error) {
return {
statusCode: 422,
body: JSON.stringify(
{
- "status": "can not send the message"
+ "status": "423",
+ ...error
}
)
}
diff --git a/functions/send-emails/invite-en.html b/functions/send-emails/invite-en.html
deleted file mode 100644
index a399098..0000000
--- a/functions/send-emails/invite-en.html
+++ /dev/null
@@ -1,218 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{#i18n 'email.happy' }}We are happy to send you this email! You will be able to vote using majority judgment.{{/i18n}}
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
- |
-
-
-
-
-
-
-
- {{#i18n 'email.hello'}}Hi, there! 🙂{{/i18n}}
- |
-
-
- |
-
-
-
-
-
-
-
-
-
- {{#i18n 'email.happy'}}We are happy to send you this email! You will be able to vote using majority judgment.{{/i18n}}
-
- |
-
-
-
-
-
- {{#i18n 'email.why'}}This email was sent to you because your email address was entered to participate in the vote on the subject:{{/i18n}}
-
- {{title}}
-
- |
-
-
-
-
-
- |
-
-
-
-
-
- {{#i18n 'email.copyLink' }}If that doesn't work, copy and paste the following link into your browser:{{/i18n}}
-
- %recipient.urlVote%
-
- |
-
-
-
-
-
- {{#i18n 'email.linkResult' }}The results will be available with the following link when the vote is finished:{{/i18n}}
-
- %recipient.urlResult%
-
- |
-
-
-
-
- {{#i18n 'email.bye'}}Good vote{{/i18n}}, {{#i18n 'common.mieuxvoter'}}Mieux Voter{{/i18n}}
- |
-
-
- |
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
- {{#i18n email.why }}You received this email because someone invited you to vote.{{/i18n}}
-
- |
-
-
-
-
- {{#i18n mieuxvoter }}Mieux Voter{{/i18n}} - app@mieuxvoter.fr
- |
-
-
- |
-
-
-
-
diff --git a/functions/send-emails/invite-en.txt b/functions/send-emails/invite-en.txt
deleted file mode 100644
index f4b8f60..0000000
--- a/functions/send-emails/invite-en.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-{{i18n 'email.hello'}}Hi there! 🙂{{i18n}}
-
-{{i18n 'email.happy'}}We are happy to send you this email! You will be able to vote using majority judgment.{{i18n}}
-
-{{i18n 'email.why'}}This email was sent to you because your email was filled out to participate in the vote on the subject:{{i18n}}
-
-{{ title }}
-
-{{i18n 'email.linkVote' }}The link for the vote is as follows:{{i18n}}
-
-%recipient.urlVote%
-
-{{i18n 'email.linkResult' }}The link that will give you the results when they are available is as follows:{{i18n}}
-
-%recipient.urlResult%
-
-{{i18n 'email.bye'}}Good vote{{i18n}}
-
-{{i18n 'common.mieuxvoter'}}Mieux Voter{{i18n}}
diff --git a/functions/send-emails/invite-fr.txt b/functions/send-emails/invite-fr.txt
deleted file mode 100644
index 9ec0f3e..0000000
--- a/functions/send-emails/invite-fr.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Bonjour ! 🙂
-
-Vous avez été invité·e à participer à l'élection suivante :
-
-{{ title }}
-
-Le lien pour voter est le suivant :
-
-%recipient.urlVote%
-
-A la fin de l'élection, vous pourrez accéder aux résultats en cliquant sur ce lien :
-
-%recipient.urlResult%
-
-Bon vote ! 🤗
-
-Mieux Voter
diff --git a/functions/send-emails/invite.html b/functions/send-emails/invite.html
index a399098..bd4db4c 100644
--- a/functions/send-emails/invite.html
+++ b/functions/send-emails/invite.html
@@ -71,7 +71,7 @@
- {{#i18n 'email.happy' }}We are happy to send you this email! You will be able to vote using majority judgment.{{/i18n}}
+ {{#i18n 'email.invite.happy' }}{{/i18n}}
@@ -81,7 +81,7 @@
-
+
|
@@ -108,7 +108,7 @@
- {{#i18n 'email.happy'}}We are happy to send you this email! You will be able to vote using majority judgment.{{/i18n}}
+ {{#i18n 'email.invite.happy'}}{{/i18n}}
|
@@ -116,9 +116,9 @@
- {{#i18n 'email.why'}}This email was sent to you because your email address was entered to participate in the vote on the subject:{{/i18n}}
+ {{#i18n 'email.invite.why'}}{{/i18n}}
- {{title}}
+ %recipient.title%
|
@@ -132,7 +132,7 @@
- {{#i18n 'common.vote' }}Vote!{{/i18n}} |
+ {{#i18n 'resource:common.vote' }}Vote!{{/i18n}}
@@ -144,9 +144,14 @@
- {{#i18n 'email.copyLink' }}If that doesn't work, copy and paste the following link into your browser:{{/i18n}}
+ {{#i18n 'email.copyLink' }}{{/i18n}}
- %recipient.urlVote%
+
+ %recipient.urlVote%
+
|
@@ -154,16 +159,21 @@
- {{#i18n 'email.linkResult' }}The results will be available with the following link when the vote is finished:{{/i18n}}
+ {{#i18n 'email.invite.linkResult' }}{{/i18n}}
- %recipient.urlResult%
+
+ %recipient.urlResult%
+
|
- {{#i18n 'email.bye'}}Good vote{{/i18n}}, {{#i18n 'common.mieuxvoter'}}Mieux Voter{{/i18n}}
+ {{#i18n 'email.bye'}}{{/i18n}} {{#i18n 'resource:common.better-vote'}}{{/i18n}}
|
@@ -177,13 +187,13 @@
-
- {{#i18n 'email.aboutjm'}}Need any further information?{{/i18n}}
+
+ {{#i18n 'email.about-mj'}}{{/i18n}}
-
- {{#i18n 'common.helpus'}}Do you want to help us?{{/i18n}}
+
+ {{#i18n 'resource:common.support-us'}}{{/i18n}}
|
@@ -200,14 +210,14 @@
- {{#i18n email.why }}You received this email because someone invited you to vote.{{/i18n}}
+ {{#i18n email.why }}{{/i18n}}
|
- {{#i18n mieuxvoter }}Mieux Voter{{/i18n}} - app@mieuxvoter.fr
+ {{#i18n resource:common.better-vote }}{{/i18n}} - {{ from_email_address }}
|
diff --git a/functions/send-emails/invite.txt b/functions/send-emails/invite.txt
index 92a8522..9e546cb 100644
--- a/functions/send-emails/invite.txt
+++ b/functions/send-emails/invite.txt
@@ -1,19 +1,19 @@
-{{#i18n 'email.hello'}}Hi there! 🙂{{/i18n}}
+{{#i18n 'email.hello'}}{{/i18n}}
-{{#i18n 'email.happy'}}We are happy to send you this email! You will be able to vote using majority judgment.{{/i18n}}
+{{#i18n 'email.invite.happy'}}{{/i18n}}
-{{#i18n 'email.why'}}This email was sent to you because your email was filled out to participate in the vote on the subject:{{/i18n}}
+{{#i18n 'email.invite.why'}}{{/i18n}}
%recipient.title%
-{{#i18n 'email.linkVote' }}The link for the vote is as follows:{{/i18n}}
+{{#i18n 'email.invite.linkVote' }}{{/i18n}}
%recipient.urlVote%
-{{#i18n 'email.linkResult' }}The link that will give you the results when they are available is as follows:{{/i18n}}
+{{#i18n 'email.invite.linkResult' }}{{/i18n}}
%recipient.urlResult%
-{{#i18n 'email.bye'}}Good vote{{/i18n}}
+{{#i18n 'email.bye'}}{{/i18n}}
-{{#i18n 'common.mieuxvoter'}}Mieux Voter{{/i18n}}
+{{#i18n 'common.better-vote'}}{{/i18n}}
diff --git a/functions/test/test.ts b/functions/test/test.ts
new file mode 100644
index 0000000..0ed6c84
--- /dev/null
+++ b/functions/test/test.ts
@@ -0,0 +1,16 @@
+console.log(__dirname)
+
+const send = async (event) => {
+ /**
+ * Send a mail using Mailgun
+ */
+ return {
+ statusCode: 405,
+ body: __dirname,
+ headers: {Allow: 'POST'},
+ };
+
+};
+
+exports.handler = send
+
diff --git a/netlify.toml b/netlify.toml
index 4423fc7..9209742 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -6,3 +6,6 @@
[dev]
command = "npm run dev"
+[functions]
+ included_files = ["functions/**"]
+
diff --git a/package-lock.json b/package-lock.json
index d2462e5..054ab04 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -36,6 +36,7 @@
"react-i18next": "^12.0.0",
"reactstrap": "^9.1.4",
"sass": "^1.32.13",
+ "ts-node": "^10.9.1",
"typescript": "^4.8.4"
},
"devDependencies": {
@@ -405,6 +406,26 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
"node_modules/@dnd-kit/accessibility": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.0.1.tgz",
@@ -630,7 +651,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
- "peer": true,
"engines": {
"node": ">=6.0.0"
}
@@ -647,8 +667,7 @@
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
- "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
- "peer": true
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.17",
@@ -1037,6 +1056,26 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
+ "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA=="
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag=="
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow=="
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
+ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ=="
+ },
"node_modules/@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
@@ -1054,8 +1093,7 @@
"node_modules/@types/node": {
"version": "18.11.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
- "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
- "dev": true
+ "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg=="
},
"node_modules/@types/prop-types": {
"version": "15.7.5",
@@ -1214,6 +1252,14 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
+ "node_modules/acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -1261,6 +1307,11 @@
"node": ">= 8"
}
},
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
+ },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -1669,6 +1720,11 @@
"url": "https://opencollective.com/core-js"
}
},
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -1791,6 +1847,14 @@
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
},
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -3417,6 +3481,11 @@
"form-data": "^4.0.0"
}
},
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -4516,6 +4585,48 @@
"node": ">=8.0"
}
},
+ "node_modules/ts-node": {
+ "version": "10.9.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+ "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
"node_modules/tsconfig-paths": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
@@ -4671,6 +4782,11 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="
+ },
"node_modules/void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
@@ -4740,6 +4856,14 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -5018,6 +5142,25 @@
"to-fast-properties": "^2.0.0"
}
},
+ "@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "requires": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "dependencies": {
+ "@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "requires": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ }
+ }
+ },
"@dnd-kit/accessibility": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.0.1.tgz",
@@ -5177,8 +5320,7 @@
"@jridgewell/resolve-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
- "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
- "peer": true
+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w=="
},
"@jridgewell/set-array": {
"version": "1.1.2",
@@ -5189,8 +5331,7 @@
"@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
- "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
- "peer": true
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
},
"@jridgewell/trace-mapping": {
"version": "0.3.17",
@@ -5437,6 +5578,26 @@
"tslib": "^2.4.0"
}
},
+ "@tsconfig/node10": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
+ "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA=="
+ },
+ "@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag=="
+ },
+ "@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow=="
+ },
+ "@tsconfig/node16": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
+ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ=="
+ },
"@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
@@ -5454,8 +5615,7 @@
"@types/node": {
"version": "18.11.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
- "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
- "dev": true
+ "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg=="
},
"@types/prop-types": {
"version": "15.7.5",
@@ -5553,6 +5713,11 @@
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"requires": {}
},
+ "acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA=="
+ },
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -5587,6 +5752,11 @@
"picomatch": "^2.0.4"
}
},
+ "arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
+ },
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -5881,6 +6051,11 @@
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz",
"integrity": "sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA=="
},
+ "create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
+ },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -5964,6 +6139,11 @@
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
},
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
+ },
"dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -7138,6 +7318,11 @@
}
}
},
+ "make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
+ },
"merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -7856,6 +8041,26 @@
"is-number": "^7.0.0"
}
},
+ "ts-node": {
+ "version": "10.9.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+ "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
+ "requires": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ }
+ },
"tsconfig-paths": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
@@ -7963,6 +8168,11 @@
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"requires": {}
},
+ "v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="
+ },
"void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
@@ -8017,6 +8227,11 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
+ "yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
+ },
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index 25deb61..b69d3c7 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,7 @@
"react-i18next": "^12.0.0",
"reactstrap": "^9.1.4",
"sass": "^1.32.13",
+ "ts-node": "^10.9.1",
"typescript": "^4.8.4"
},
"devDependencies": {
diff --git a/public/locales/en/email.json b/public/locales/en/email.json
new file mode 100644
index 0000000..e21b50b
--- /dev/null
+++ b/public/locales/en/email.json
@@ -0,0 +1,16 @@
+{
+ "email.hello": "Hi there! 🙂",
+ "email.invite.subject": "You are invited to vote",
+ "email.invite.happy": "We are happy to send you this email! You will be able to vote using majority judgment.",
+ "email.invite.why": "This email was sent to you because your email was filled out to participate in the vote on the subject:",
+ "email.invite.linkVote": "The link for the vote is as follows:",
+ "email.invite.linkResult": "The link that will give you the results when they are available is as follows:",
+ "email.invite.bye": "Good bye",
+ "email.admin.subject": "Manage your election",
+ "email.admin.happy": "We are happy to send you this email! You have created a vote using majority judgment.",
+ "email.admin.why": "This email was sent to you since you have asked us to send the admin link",
+ "email.admin.linkAdmin": "The below admin link allows you to manage your election.",
+ "email.bye": "Good bye",
+ "email.copyLink": "If that doesn't work, copy and paste the following link into your browser:",
+ "email.about-mj": "Need any further information?"
+}
diff --git a/public/locales/en/resource.json b/public/locales/en/resource.json
index fce6e8c..5ecbbde 100644
--- a/public/locales/en/resource.json
+++ b/public/locales/en/resource.json
@@ -1,98 +1,100 @@
{
- "home.motto": "Simple and free",
- "home.slogan": "Organize a vote with majority judgment",
- "logo.alt": "Logo of Better Vote",
- "home.writeQuestion": "Write here your question or describe your vote.",
- "home.start": "Start a vote",
- "home.noAds": "No advertising or ad cookies",
- "home.advantage-1-title": "Simple",
- "home.advantage-1-desc": "Create a vote in less than 1 minute!",
- "home.advantage-2-title": "Free",
- "home.advantage-2-desc": "Send invites without any limitations!",
- "home.advantage-3-title": "Respecting your privacy",
- "home.advantage-3-desc": "No personal data is recorded",
- "home.experience-title": "A democratic and intuitive voting experience",
- "home.experience-1-title": "Express your full opinion.",
- "home.experience-1-desc": "With majority judgment, each candidate is evaluated on a grid of mentions. Strategic voting has no use anymore.",
- "home.experience-2-title": "Get the best possible consensus.",
- "home.experience-2-desc": "The merit profile provides an accurate picture of the voters' opinions. The winner of the vote is the one with the best majority rating.",
- "home.experience-call-to-action": "Find out about the majority judgment",
- "home.alt-icon-ballot-box": "icon of a ballot box",
- "home.alt-icon-envelop": "icon of an envelop",
- "home.alt-icon-respect": "icon of hands holding each other",
- "home.alt-icon-ballot": "icon of a ballot",
- "menu.majority-judgment": "Majority judgment",
- "menu.whoarewe": "Who are we?",
- "menu.faq": "FAQ",
- "menu.news": "News",
- "menu.contact-us": "Contact us",
- "common.error": "Oh no... An error has occured...",
- "common.share": "Share the application Better Vote",
- "common.share-short": "Share the application",
- "common.save": "Save",
- "common.back-homepage": "Return to home page",
- "common.support-us": "Support us",
- "common.thumbnail": "Thumbnail",
- "common.name": "Name",
- "common.description": "Description",
- "common.cancel": "Cancel",
- "common.grades": "Grades",
- "common.invites": "invites",
- "common.days": "days",
- "common.send": "Send",
- "common.the-vote": "The vote",
- "common.the-params": "The parameters",
- "error.help": "Ask for our help",
- "error.at-least-2-candidates": "At least two candidates are required.",
- "error.no-title": "Please add a title to your election.",
- "grades.very-good": "Very good",
- "grades.good": "Good",
- "grades.passable": "Passable",
- "grades.inadequate": "Inadequate",
- "grades.mediocre": "Mediocre",
- "admin.date-limit": "Set a deadline for voting",
- "admin.step-candidate": "Candidates",
- "admin.step-params": "Parameters",
- "admin.step-confirm": "Confirm",
- "admin.add-candidates": "Add the candidates.",
- "admin.add-candidate": "Add a candidate",
- "admin.add-candidate-desc": "Add a picture, a name, and a description of the candidate.",
- "admin.add-grade": "Add a grade",
- "admin.add-grade-desc": "The name of the grade must be unique.",
- "admin.grade-name-placeholder": "Add the name of the grade",
- "admin.candidate-confirm-del": "You want to remove a candidate",
- "admin.candidate-confirm-back": "No, I keep it",
- "admin.candidate-confirm-ok": "Delete",
- "admin.candidate-name-placeholder": "Add the name or the title of the candidate.",
- "admin.candidate-desc-placeholder": "Add the description of the candidate.",
- "admin.candidates-submit": "Validate the candidates",
- "admin.candidates-back-step": "Back to candidates",
- "admin.modal-title": "Managing an election",
- "admin.modal-desc": "This link allows you to modify your election. Keep it carefully, or fill out this form to receive a copy by mail.",
- "admin.modal-disclaimer": "We do not store any mail. Thus, we will not send you any advertising content.",
- "admin.modal-email-placeholder": "Your mail address",
- "admin.params-submit": "Validate the parameters",
- "admin.params-title": "Your parameters",
- "admin.access-results": "Immediate access to the results",
- "admin.access-results-desc": "No one can access to the results as long as the vote is not closed.",
- "admin.limit-duration": "Limit the length of the vote",
- "admin.limit-duration-desc": "",
- "admin.photo": "Picture",
- "admin.optional": "optional",
- "admin.photo-import": "Import a picture",
- "admin.photo-type": "Supported type:",
- "admin.grades-desc": "You can choose to customize the name and the number of mentions. If in doubt, leave the grades as is.",
- "admin.ending-in": "In",
- "admin.until": "Until",
- "admin.private-title": "Private vote",
- "admin.private-desc": "Only participants who received an invite by email will be able to vote",
- "admin.private-tip": "You can copy-paste a list of emails from a spreadsheet.",
- "admin.private-placeholder": "Add here the emails of the participants.",
- "admin.confirm-question": "Question of your vote",
- "admin.confirm-candidates": "Candidates",
- "admin.confirm-submit": "Start the vote",
- "admin.confirm-title": "Confirm your vote",
- "admin.success-election": "The vote has been created with success!",
- "admin.success-emails": "The voting link has been sent by emails to the participants.",
- "admin.go-to-admin": "Manage the vote"
+ "home.motto": "Simple and free",
+ "home.slogan": "Organize a vote with majority judgment",
+ "logo.alt": "Logo of Better Vote",
+ "home.writeQuestion": "Write here your question or describe your vote.",
+ "home.start": "Start a vote",
+ "home.noAds": "No advertising or ad cookies",
+ "home.advantage-1-title": "Simple",
+ "home.advantage-1-desc": "Create a vote in less than 1 minute!",
+ "home.advantage-2-title": "Free",
+ "home.advantage-2-desc": "Send invites without any limitations!",
+ "home.advantage-3-title": "Respecting your privacy",
+ "home.advantage-3-desc": "No personal data is recorded",
+ "home.experience-title": "A democratic and intuitive voting experience",
+ "home.experience-1-title": "Express your full opinion.",
+ "home.experience-1-desc": "With majority judgment, each candidate is evaluated on a grid of mentions. Strategic voting has no use anymore.",
+ "home.experience-2-title": "Get the best possible consensus.",
+ "home.experience-2-desc": "The merit profile provides an accurate picture of the voters' opinions. The winner of the vote is the one with the best majority rating.",
+ "home.experience-call-to-action": "Find out about the majority judgment",
+ "home.alt-icon-ballot-box": "icon of a ballot box",
+ "home.alt-icon-envelop": "icon of an envelop",
+ "home.alt-icon-respect": "icon of hands holding each other",
+ "home.alt-icon-ballot": "icon of a ballot",
+ "menu.majority-judgment": "Majority judgment",
+ "menu.whoarewe": "Who are we?",
+ "menu.faq": "FAQ",
+ "menu.news": "News",
+ "menu.contact-us": "Contact us",
+ "common.error": "Oh no... An error has occured...",
+ "common.better-vote": "Better Vote",
+ "common.share": "Share the application Better Vote",
+ "common.share-short": "Share the application",
+ "common.save": "Save",
+ "common.back-homepage": "Return to home page",
+ "common.support-us": "Support us",
+ "common.thumbnail": "Thumbnail",
+ "common.name": "Name",
+ "common.description": "Description",
+ "common.cancel": "Cancel",
+ "common.grades": "Grades",
+ "common.invites": "invites",
+ "common.days": "days",
+ "common.send": "Send",
+ "common.vote": "Vote",
+ "common.the-vote": "The vote",
+ "common.the-params": "The parameters",
+ "error.help": "Ask for our help",
+ "error.at-least-2-candidates": "At least two candidates are required.",
+ "error.no-title": "Please add a title to your election.",
+ "grades.very-good": "Very good",
+ "grades.good": "Good",
+ "grades.passable": "Passable",
+ "grades.inadequate": "Inadequate",
+ "grades.mediocre": "Mediocre",
+ "admin.date-limit": "Set a deadline for voting",
+ "admin.step-candidate": "Candidates",
+ "admin.step-params": "Parameters",
+ "admin.step-confirm": "Confirm",
+ "admin.add-candidates": "Add the candidates.",
+ "admin.add-candidate": "Add a candidate",
+ "admin.add-candidate-desc": "Add a picture, a name, and a description of the candidate.",
+ "admin.add-grade": "Add a grade",
+ "admin.add-grade-desc": "The name of the grade must be unique.",
+ "admin.grade-name-placeholder": "Add the name of the grade",
+ "admin.candidate-confirm-del": "You want to remove a candidate",
+ "admin.candidate-confirm-back": "No, I keep it",
+ "admin.candidate-confirm-ok": "Delete",
+ "admin.candidate-name-placeholder": "Add the name or the title of the candidate.",
+ "admin.candidate-desc-placeholder": "Add the description of the candidate.",
+ "admin.candidates-submit": "Validate the candidates",
+ "admin.candidates-back-step": "Back to candidates",
+ "admin.modal-title": "Managing an election",
+ "admin.modal-desc": "This link allows you to modify your election. Keep it carefully, or fill out this form to receive a copy by mail.",
+ "admin.modal-disclaimer": "We do not store any mail. Thus, we will not send you any advertising content.",
+ "admin.modal-email-placeholder": "Your mail address",
+ "admin.params-submit": "Validate the parameters",
+ "admin.params-title": "Your parameters",
+ "admin.access-results": "Immediate access to the results",
+ "admin.access-results-desc": "No one can access to the results as long as the vote is not closed.",
+ "admin.limit-duration": "Limit the length of the vote",
+ "admin.limit-duration-desc": "",
+ "admin.photo": "Picture",
+ "admin.optional": "optional",
+ "admin.photo-import": "Import a picture",
+ "admin.photo-type": "Supported type:",
+ "admin.grades-desc": "You can choose to customize the name and the number of mentions. If in doubt, leave the grades as is.",
+ "admin.ending-in": "In",
+ "admin.until": "Until",
+ "admin.private-title": "Private vote",
+ "admin.private-desc": "Only participants who received an invite by email will be able to vote",
+ "admin.private-tip": "You can copy-paste a list of emails from a spreadsheet.",
+ "admin.private-placeholder": "Add here the emails of the participants.",
+ "admin.confirm-question": "Question of your vote",
+ "admin.confirm-candidates": "Candidates",
+ "admin.confirm-submit": "Start the vote",
+ "admin.confirm-title": "Confirm your vote",
+ "admin.success-election": "The vote has been created with success!",
+ "admin.success-emails": "The voting link has been sent by emails to the participants.",
+ "admin.go-to-admin": "Manage the vote"
}
diff --git a/public/locales/fr/email.json b/public/locales/fr/email.json
new file mode 100644
index 0000000..b99748f
--- /dev/null
+++ b/public/locales/fr/email.json
@@ -0,0 +1,15 @@
+{
+ "email.hello": "Bonjour ! 🙂",
+ "email.invite.subject": "Vous participez au vote en cours",
+ "email.invite.happy": "Nous sommes très heureux de vous envoyer ce courriel ! Vous allez pouvoir voter en utilisant le jugement majoritaire.",
+ "email.invite.why": "Ce courriel vous a été envoyé, car l'organisateur du vote vous a ajoutés dans la liste des participants. Le vote porte sur :",
+ "email.invite.linkVote": "Le lien pour voter est ci-dessous",
+ "email.invite.linkResult": "Le lien pour voir les résultats est ci-dessous. Conservez le bien !",
+ "email.admin.subject": "GĂ©rez votre Ă©lection",
+ "email.admin.happy": "Nous sommes très heureux de vous envoyer ce courriel ! Vous venez de créer une élection avec le jugement majoritaire.",
+ "email.admin.why": "Vous recevez ce courriel parce que vous nous avez chargé de vous transmettre le lien d'administration. Gardez le précieusement : un autre lien ne pourra leien ne pourra pas vous être partagé.",
+ "email.admin.linkAdmin": "Ce lien ci-dessous vous permet de gérer votre élection.",
+ "email.bye": "Au revoir !",
+ "email.copyLink": "Si cela ne fonctionne pas, copiez-collez le lien suivant dans votre navigateur :",
+ "email.about-mj": "Besoin de plus d'information ?"
+}
diff --git a/public/locales/fr/resource.json b/public/locales/fr/resource.json
index 3a29259..c4d0771 100644
--- a/public/locales/fr/resource.json
+++ b/public/locales/fr/resource.json
@@ -1,98 +1,100 @@
{
- "home.motto": "Simple et gratuit",
- "home.slogan": "Organisez un vote avec le jugement majoritaire",
- "logo.alt": "Logo de Mieux Voter",
- "home.writeQuestion": "Posez la question de votre vote ici.",
- "home.start": "C'est parti",
- "home.noAds": "Pas de publicités, ni de cookies publicitaires",
- "home.advantage-1-title": "Simple",
- "home.advantage-1-desc": "Créez un vote en moins d’une minute.",
- "home.advantage-2-title": "Gratuit",
- "home.advantage-2-desc": "Envoyez des invitations par courriel sans limite d'envoi.",
- "home.advantage-3-title": "Respect de votre vie privée",
- "home.advantage-3-desc": "Aucune donnée personnelle n'est enregistrée",
- "home.experience-title": "Une expérience de vote démocratique et intuitive",
- "home.experience-1-title": "Exprimez toute votre opinion.",
- "home.experience-1-desc": "Au jugement majoritaire, chaque candidat est évalué sur une grille de mention. Vous n'aurez plus besoin de faire un vote stratégique.",
- "home.experience-2-title": "Obtenez le meilleur consensus.",
- "home.experience-2-desc": "Le profil des mérites dresse un panorama précis de l’opinion des électeurs. Le gagnant du vote est celui qui est la meilleure mention majoritaire.",
- "home.experience-call-to-action": "DĂ©couvrez le jugement majoritaire",
- "home.alt-icon-ballot-box": "icone d'urne",
- "home.alt-icon-envelop": "icone d'enveloppe",
- "home.alt-icon-respect": "icone de mains qui se serrent",
- "home.alt-icon-ballot": "icone d'un bulletin de vote",
- "menu.majority-judgment": "Jugement majoritaire",
- "menu.whoarewe": "Qui sommes-nous ?",
- "menu.faq": "FAQ",
- "menu.news": "Actualités",
- "menu.contact-us": "Nous contacter",
- "common.error": "Oh non ! Une erreur s'est produite...",
- "common.share": "Partagez l'application Mieux voter",
- "common.share-short": "Partagez l'application",
- "common.back-homepage": "Revenir sur la page d'accueil",
- "common.support-us": "Soutenez nous",
- "common.save": "Sauvegarder",
- "common.thumbnail": "Image miniature",
- "common.name": "Nom",
- "common.description": "Description",
- "common.cancel": "Annuler",
- "common.grades": "Mentions",
- "common.days": "jours",
- "common.invites": "invitations",
- "common.send": "Envoyer",
- "common.the-vote": "Le vote",
- "common.the-params": "Les paramètres",
- "error.help": "Besoin d'aide ?",
- "error.at-least-2-candidates": "Ajoutez au moins deux candidats.",
- "error.no-title": "Ajoutez un titre Ă l'Ă©lection.",
- "grades.very-good": "Très bien",
- "grades.good": "Bien",
- "grades.passable": "Passable",
- "grades.inadequate": "Insuffisant",
- "grades.mediocre": "MĂ©diocre",
- "admin.date-limit": "Fixer une date limite pour le vote",
- "admin.step-candidate": "Les candidats",
- "admin.step-params": "Paramètres du vote",
- "admin.step-confirm": "Confirmation",
- "admin.add-candidates": "Ajouter les candidats.",
- "admin.add-candidate": "Ajouter un candidat",
- "admin.candidate-name-placeholder": "Ajouter le nom ou le titre du candidat.",
- "admin.candidate-desc-placeholder": "Ajouter la description du candidat.",
- "admin.add-candidate-desc": "Ajouter une photo, le nom et une description au candidat.",
- "admin.add-grade": "Ajouter une mention",
- "admin.add-grade-desc": "Le nom de la mention doit ĂŞtre unique.",
- "admin.grade-name-placeholder": "Ajoutez le nom de la mention.",
- "admin.candidate-confirm-del": "Vous souhaitez supprimer un candidat",
- "admin.candidate-confirm-back": "Non, je le garde",
- "admin.candidate-confirm-ok": "Supprimer",
- "admin.candidates-submit": "Valider les candidats",
- "admin.candidates-back-step": "Retour aux candidats",
- "admin.params-submit": "Valider les paramètres",
- "admin.params-title": "Vos paramètres",
- "admin.access-results": "Accès immédiat aux résultats",
- "admin.access-results-desc": "Personne ne pourra accéder aux résultats tant que le vote n'est pas clôturé.",
- "admin.limit-duration": "Limiter la durée du vote",
- "admin.limit-duration-desc": "",
- "admin.modal-title": "Administration du vote",
- "admin.modal-desc": "Ce lien vous permet de modifier votre vote. Conservez le précieusement, ou remplissez votre adresse email ci-dessous pour en recevoir une copie",
- "admin.modal-disclaimer": "Nous ne stockons aucun email. Nous ne vous enverrons donc aucun contenu publicitaire.",
- "admin.modal-email-placeholder": "Votre adresse email",
- "admin.photo": "Photo",
- "admin.optional": "facultatif",
- "admin.photo-import": "Importer une photo",
- "admin.photo-type": "Format supporté :",
- "admin.grades-desc": "Vous pouvez choisir de personaliser le nom et le nombre de mentions. En cas de doute, gardez les mentions par défaut.",
- "admin.ending-in": "Dans",
- "admin.until": "Jusqu'au",
- "admin.private-title": "Vote privé",
- "admin.private-desc": "Uniquement les personnes invités par mail pourront participé au vote",
- "admin.private-tip": "Vous pouvez copier-coller une liste d'emails depuis un tableur.",
- "admin.private-placeholder": "Ajoutez ici les emails des participants.",
- "admin.confirm-question": "Question de votre vote",
- "admin.confirm-candidates": "Candidats",
- "admin.confirm-submit": "DĂ©marrer le vote",
- "admin.confirm-title": "Confirmer votre vote",
- "admin.success-election": "Le vote a été créé avec succès",
- "admin.success-emails": "Le lien du vote a été envoyé par courriel aux participants.",
- "admin.go-to-admin": "Administrez le vote"
+ "home.motto": "Simple et gratuit",
+ "home.slogan": "Organisez un vote avec le jugement majoritaire",
+ "logo.alt": "Logo de Mieux Voter",
+ "home.writeQuestion": "Posez la question de votre vote ici.",
+ "home.start": "C'est parti",
+ "home.noAds": "Pas de publicités, ni de cookies publicitaires",
+ "home.advantage-1-title": "Simple",
+ "home.advantage-1-desc": "Créez un vote en moins d’une minute.",
+ "home.advantage-2-title": "Gratuit",
+ "home.advantage-2-desc": "Envoyez des invitations par courriel sans limite d'envoi.",
+ "home.advantage-3-title": "Respect de votre vie privée",
+ "home.advantage-3-desc": "Aucune donnée personnelle n'est enregistrée",
+ "home.experience-title": "Une expérience de vote démocratique et intuitive",
+ "home.experience-1-title": "Exprimez toute votre opinion.",
+ "home.experience-1-desc": "Au jugement majoritaire, chaque candidat est évalué sur une grille de mention. Vous n'aurez plus besoin de faire un vote stratégique.",
+ "home.experience-2-title": "Obtenez le meilleur consensus.",
+ "home.experience-2-desc": "Le profil des mérites dresse un panorama précis de l’opinion des électeurs. Le gagnant du vote est celui qui est la meilleure mention majoritaire.",
+ "home.experience-call-to-action": "DĂ©couvrez le jugement majoritaire",
+ "home.alt-icon-ballot-box": "icone d'urne",
+ "home.alt-icon-envelop": "icone d'enveloppe",
+ "home.alt-icon-respect": "icone de mains qui se serrent",
+ "home.alt-icon-ballot": "icone d'un bulletin de vote",
+ "menu.majority-judgment": "Jugement majoritaire",
+ "menu.whoarewe": "Qui sommes-nous ?",
+ "menu.faq": "FAQ",
+ "menu.news": "Actualités",
+ "menu.contact-us": "Nous contacter",
+ "common.error": "Oh non ! Une erreur s'est produite...",
+ "common.better-vote": "Mieux Voter",
+ "common.share": "Partagez l'application Mieux voter",
+ "common.share-short": "Partagez l'application",
+ "common.back-homepage": "Revenir sur la page d'accueil",
+ "common.support-us": "Soutenez nous",
+ "common.save": "Sauvegarder",
+ "common.thumbnail": "Image miniature",
+ "common.name": "Nom",
+ "common.description": "Description",
+ "common.cancel": "Annuler",
+ "common.grades": "Mentions",
+ "common.days": "jours",
+ "common.invites": "invitations",
+ "common.send": "Envoyer",
+ "common.the-vote": "Le vote",
+ "common.the-params": "Les paramètres",
+ "common.vote": "Voter",
+ "error.help": "Besoin d'aide ?",
+ "error.at-least-2-candidates": "Ajoutez au moins deux candidats.",
+ "error.no-title": "Ajoutez un titre Ă l'Ă©lection.",
+ "grades.very-good": "Très bien",
+ "grades.good": "Bien",
+ "grades.passable": "Passable",
+ "grades.inadequate": "Insuffisant",
+ "grades.mediocre": "MĂ©diocre",
+ "admin.date-limit": "Fixer une date limite pour le vote",
+ "admin.step-candidate": "Les candidats",
+ "admin.step-params": "Paramètres du vote",
+ "admin.step-confirm": "Confirmation",
+ "admin.add-candidates": "Ajouter les candidats.",
+ "admin.add-candidate": "Ajouter un candidat",
+ "admin.candidate-name-placeholder": "Ajouter le nom ou le titre du candidat.",
+ "admin.candidate-desc-placeholder": "Ajouter la description du candidat.",
+ "admin.add-candidate-desc": "Ajouter une photo, le nom et une description au candidat.",
+ "admin.add-grade": "Ajouter une mention",
+ "admin.add-grade-desc": "Le nom de la mention doit ĂŞtre unique.",
+ "admin.grade-name-placeholder": "Ajoutez le nom de la mention.",
+ "admin.candidate-confirm-del": "Vous souhaitez supprimer un candidat",
+ "admin.candidate-confirm-back": "Non, je le garde",
+ "admin.candidate-confirm-ok": "Supprimer",
+ "admin.candidates-submit": "Valider les candidats",
+ "admin.candidates-back-step": "Retour aux candidats",
+ "admin.params-submit": "Valider les paramètres",
+ "admin.params-title": "Vos paramètres",
+ "admin.access-results": "Accès immédiat aux résultats",
+ "admin.access-results-desc": "Personne ne pourra accéder aux résultats tant que le vote n'est pas clôturé.",
+ "admin.limit-duration": "Limiter la durée du vote",
+ "admin.limit-duration-desc": "",
+ "admin.modal-title": "Administration du vote",
+ "admin.modal-desc": "Ce lien vous permet de modifier votre vote. Conservez le précieusement, ou remplissez votre adresse email ci-dessous pour en recevoir une copie",
+ "admin.modal-disclaimer": "Nous ne stockons aucun email. Nous ne vous enverrons donc aucun contenu publicitaire.",
+ "admin.modal-email-placeholder": "Votre adresse email",
+ "admin.photo": "Photo",
+ "admin.optional": "facultatif",
+ "admin.photo-import": "Importer une photo",
+ "admin.photo-type": "Format supporté :",
+ "admin.grades-desc": "Vous pouvez choisir de personaliser le nom et le nombre de mentions. En cas de doute, gardez les mentions par défaut.",
+ "admin.ending-in": "Dans",
+ "admin.until": "Jusqu'au",
+ "admin.private-title": "Vote privé",
+ "admin.private-desc": "Uniquement les personnes invités par mail pourront participé au vote",
+ "admin.private-tip": "Vous pouvez copier-coller une liste d'emails depuis un tableur.",
+ "admin.private-placeholder": "Ajoutez ici les emails des participants.",
+ "admin.confirm-question": "Question de votre vote",
+ "admin.confirm-candidates": "Candidats",
+ "admin.confirm-submit": "DĂ©marrer le vote",
+ "admin.confirm-title": "Confirmer votre vote",
+ "admin.success-election": "Le vote a été créé avec succès",
+ "admin.success-emails": "Le lien du vote a été envoyé par courriel aux participants.",
+ "admin.go-to-admin": "Administrez le vote"
}
diff --git a/tests/admin-en.json b/tests/admin-en.json
new file mode 100644
index 0000000..e2b0b74
--- /dev/null
+++ b/tests/admin-en.json
@@ -0,0 +1,14 @@
+{
+ "recipients": {
+ "app@mieuxvoter.fr": {
+ "title": "Test",
+ "urlAdmin": "foo"
+ },
+ "tech@mieuxvoter.fr": {
+ "title": "Test",
+ "urlAdmin": "foo"
+ }
+ },
+ "action": "admin",
+ "locale": "en"
+}
diff --git a/tests/admin-fr.json b/tests/admin-fr.json
new file mode 100644
index 0000000..a2354d3
--- /dev/null
+++ b/tests/admin-fr.json
@@ -0,0 +1,14 @@
+{
+ "recipients": {
+ "app@mieuxvoter.fr": {
+ "title": "Test",
+ "urlAdmin": "foo"
+ },
+ "tech@mieuxvoter.fr": {
+ "title": "Test",
+ "urlAdmin": "foo"
+ }
+ },
+ "action": "admin",
+ "locale": "fr"
+}
diff --git a/tests/invite-en.json b/tests/invite-en.json
new file mode 100644
index 0000000..910d05a
--- /dev/null
+++ b/tests/invite-en.json
@@ -0,0 +1,16 @@
+{
+ "recipients": {
+ "app@mieuxvoter.fr": {
+ "title": "Test",
+ "urlVote": "foo",
+ "urlResult": "foo"
+ },
+ "tech@mieuxvoter.fr": {
+ "title": "Test",
+ "urlVote": "foo",
+ "urlResult": "foo"
+ }
+ },
+ "action": "invite",
+ "locale": "en"
+}
diff --git a/tests/invite-fr.json b/tests/invite-fr.json
new file mode 100644
index 0000000..6da9baf
--- /dev/null
+++ b/tests/invite-fr.json
@@ -0,0 +1,16 @@
+{
+ "recipients": {
+ "app@mieuxvoter.fr": {
+ "title": "Test",
+ "urlVote": "foo",
+ "urlResult": "foo"
+ },
+ "tech@mieuxvoter.fr": {
+ "title": "Test",
+ "urlVote": "foo",
+ "urlResult": "foo"
+ }
+ },
+ "action": "invite",
+ "locale": "fr"
+}
diff --git a/tests/netlify-send-emails.sh b/tests/netlify-send-emails.sh
index 13254b4..f1d89d0 100755
--- a/tests/netlify-send-emails.sh
+++ b/tests/netlify-send-emails.sh
@@ -15,5 +15,20 @@ else
fi
-netlify functions:invoke --port 9999 send-emails --payload '{"recipients"
-: {"pierrelouisguhur@gmail.com": {"title": "Test", "adminUrl": "foo"}}, "action": "invite", "locale": "gb"}'
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+
+send_emails () {
+ res=$(netlify functions:invoke --port 9999 send-emails --payload "$(cat $1)")
+ echo "$res"
+ # status=$(echo "$res" | head -n 1 | cut -d ',' -f 1 | cut -d ':' -f 2)
+ status=$(echo "$res" | jq '.["status"]')
+ if [ "$status" != '"200"' ]; then
+ echo "Issue with $1";
+ exit 2
+ fi
+}
+
+send_emails $SCRIPT_DIR/invite-en.json # && \
+#send_emails $SCRIPT_DIR/invite-fr.json && \
+#send_emails $SCRIPT_DIR/admin-en.json && \
+#send_emails $SCRIPT_DIR/admin-fr.json