From 541c9e85c71cbdf61e9600a678bb74a43988e0bf Mon Sep 17 00:00:00 2001 From: Hendrik Schaeidt Date: Sat, 11 Dec 2021 08:25:23 +0100 Subject: [PATCH] feat: add i18n support (#91) --- _locales/de/messages.json | 247 +++++++++++++++++++++++++++++ _locales/fr/messages.json | 247 +++++++++++++++++++++++++++++ background_scripts/index.js | 34 ++-- browser_action/index.html | 52 ++++-- browser_action/index.js | 12 ++ commons/VCLocalStorage.js | 2 +- content_scripts/doctolib/book.js | 53 +++---- content_scripts/doctolib/search.js | 8 +- manifest.json | 5 +- 9 files changed, 598 insertions(+), 62 deletions(-) create mode 100644 _locales/de/messages.json create mode 100644 _locales/fr/messages.json diff --git a/_locales/de/messages.json b/_locales/de/messages.json new file mode 100644 index 0000000..a33f342 --- /dev/null +++ b/_locales/de/messages.json @@ -0,0 +1,247 @@ +{ + "extensionName": { + "message": "vaccin.click", + "description": "Name der Erweiterung." + }, + "extensionDescription": { + "message": "Automatisch einen Corona-Impftermin finden und reservieren.", + "description": "Beschreibung der Erweiterung." + }, + "extensionShortDescription": { + "message": "meine Coronaimpfung in einem Klick !", + "description": "Kurzbeschreibung der Erweiterung." + }, + "resumeScan": { + "message": "Terminsuche wiederaufnehmen", + "description": "Text um die Terminsuche fortzusetzen." + }, + "pauseScan": { + "message": "Terminsuche pausieren", + "description": "Text um die Terminsuche zu pausieren." + }, + "firstAndSecondInjection": { + "message": "Erst-und Zweitimpfung", + "description": "Text der eine kombinierte Erst-und Zweitimpfung definiert." + }, + "firstInjection": { + "message": "Einzelimpfung", + "description": "Text der eine einzelne Impfung beschreibt." + }, + "secondInjection": { + "message": "Zweitimpfung", + "description": "Text der eine zweite Impfung beschreibt." + }, + "additionalInjection": { + "message": "Auffrischimpfung", + "description": "Text der alle Auffrischimpfungen beschreibt." + }, + "modernaVaccine": { + "message": "Moderna Impfstoff", + "description": "Beschreibung des Moderna Impfstoffes." + }, + "pfizerVaccine": { + "message": "Pfizer-BioNTech Impfstoff", + "description": "Beschreibung des Pfizer Impfstoffes." + }, + "disableAutoBook": { + "message": "Einen Tab öffnen sobald eine Reservierung verfügbar ist.", + "description": "Beschreibung der Funktionalität wenn die automatische Reservierung deaktiviert ist." + }, + "enableAutoBook": { + "message": "Automatisch reservieren (hierfür müssen Sie auf Doctolib eingeloggt sein)", + "description": "Beschreibung der Funktionalität wenn die automatische Reservierung aktiviert ist." + }, + "myVaccinationCenters": { + "message": "Meine Impfzentren Liste", + "description": "Überschrift der Liste aller ausgewählten Impfzentren." + }, + "findVaccinationCenters": { + "message": "Impfzentren oder Ärzte auf Doctolib finden", + "description": "Überschrift der Suchfunktion auf Doctolib." + }, + "shareOnTwitter": { + "message": "vaccin.click auf Twitter teilen", + "description": "Twitter Share Beschreibung." + }, + "advancedConfiguration": { + "message": "Erweiterte Einstellungen", + "description": "Überschrift der Erweiterten Einstellungen." + }, + "resetEverything": { + "message": "Zurücksetzen (löscht alle Daten)", + "description": "Beschreibung was beim zurücksetzen passiert." + }, + "activityLog": { + "message": "Aktivitätsprotokoll", + "description": "Text der das Aktivitätsprotokoll beschreibt." + }, + "addToMyList": { + "message": "Zur Liste hinzufügen", + "description": "Text des Buttons zum Hinzufügen zur Liste." + }, + "removeFromMyList": { + "message": "Von der Liste entfernen", + "description": "Text des Buttons zum Entfernen von der Liste." + }, + "alertWatchlistSizeExceeded": { + "message": "Um die Server von Doctolib nicht zu Überlasten ist es nicht möglich Termine in mehr als 24 Impfzentren gleichzeitig zu suchen. Löschen Sie zuerst Einträge von Ihrer Liste um weitere hinzuzufügen.", + "description": "Alert wenn zu viele Einträge auf der Watchlist sind." + }, + "clearOutdatedLocations": { + "message": "Lösche veraltete Einträge", + "description": "Log Nachricht wenn ein Cleanup stattfindet." + }, + "selectorTimeout": { + "message": "Der Selektor \"$SELECTOR$\" konnte nach 5 Sekunden nicht gefunden werden. Das ist nicht immer ein Bug.", + "description": "Log Nachricht wenn ein Selektor nicht gefunden werden konnte.", + "placeholders": { + "selector": { + "content": "$1", + "example": ".some-css-class" + } + } + }, + "waitForElementToBeRemovedNoElement": { + "message": "Des angefragte Element in waitForElementToBeRemoved existierte nicht vor dem Funktionsaufruf. Das Element muss existieren.", + "description": "Log Nachricht wenn ein Element nicht entfernt werden kann." + }, + "waitForElementToBeRemovedTimeout": { + "message": "Das angefragt Element konnte auch nach 5 Sekunden nicht entfernt werden.", + "description": "Log Nachricht wenn ein Element auch nach Timeout nicht gelöscht werden kann." + }, + "answerNoForPreviousPatientButtonNotFound": { + "message": "Konnte die Frage neuer Patient nicht mit 'Nein' beantworten.", + "description": "Log Nachricht wenn die Frage ob der Patient die Praxis bereits aufgesucht hat nicht mit 'Nein' beantwortet werden konnte." + }, + "chooseSpecialityOptionNotFound": { + "message": "Keine Übereinstimmung im Fachbereich gefunden. Verfügbare Fachbereiche : $SPECIALITIES$", + "description": "Log Nachricht wenn das Skript keine Übereinstimmung im Fachbereich gefunden hat.", + "placeholders": { + "specialities": { + "content": "$1", + "example": "Cardiologue, Dentiste, Médecin généraliste, Médecin spécialiste, Pédiatre, Psychiatre, Urologue" + } + } + }, + "checkAvailabilityStarted": { + "message": "Prüfe $URL$", + "description": "Log Nachricht wenn das Skript die Prüfung der Verfügbarkeit von einem Testzentrum startet", + "placeholders": { + "url": { + "content": "$1", + "example": "https://www.doctolib.fr/vaccination-covid-19/centre-vaccination-covid-19-paris-75-9-avenue-de-la-reunion-75016" + } + } + }, + "chooseMotiveCategoryOptionNotFound": { + "message": "Keine Übereinstimmung in der Besuchskategorie gefunden. Verfügbare Optionen : $CATEGORIES$", + "description": "Log Nachricht wenn das Skript keine Übereinstimmung in der Besuchskategorie gefunden hat.", + "placeholders": { + "categories": { + "content": "$1", + "example": "Consultation, Examen, Hospitalisation, Traitement" + } + } + }, + "injectionNotFound": { + "message": "mRNA Impfstoff nicht verfügbar $NUMBER$", + "description": "Log Nachricht wenn kein mRNA Impfstoff verfügbar ist.", + "placeholders": { + "number": { + "content": "$1", + "example": "1" + } + } + }, + "noSlot": { + "message": "Kein Termin verfügbar $NUMBER$", + "description": "Log Nachricht wenn kein Termin verfügbar ist.", + "placeholders": { + "number": { + "content": "$1", + "example": "1" + } + } + }, + "slotDateFormatNotFound": { + "message": "Termin kann nicht ausgewählt werden \"$TITLE$\"", + "description": "Log Nachricht wenn ein Termin ein nicht parsbares Datums Format hat.", + "placeholders": { + "title": { + "content": "$1", + "example": "Mardi, 14 juin 2020" + } + } + }, + "noSecondSlot": { + "message": "Kein verfügbarer Termin für die Zweitimpfung $NUMBER$", + "description": "Log Nachricht wenn ein Erst- aber kein Zweitermin verfügbar ist.", + "placeholders": { + "number": { + "content": "$1", + "example": "1" + } + } + }, + "popupConfirmationNotFound": { + "message": "Kann den Button 'Ich habe den Hinweis gelesen und akzeptiert' nicht finden.", + "description": "Log Nachricht wenn das Skript nicht automatisch den Hinweisen zustimmen kann." + }, + "manualConfirmationRequired": { + "message": "Manuelle validierung des Termins notwendig", + "description": "Log Nachricht wenn das Skript die Reservierung nicht automatisch abschließen kann, und manuell bestätigt werden muss." + }, + "locationCheckInProgress": { + "message": "Suche läuft", + "description": "Log Nachricht wenn das Skript eine Testzentrum Suche laufen lässt." + }, + "locationCheckStarted": { + "message": "Start der Überprüfung", + "description": "Log Nachricht wenn das Skript eine Testzentrum Suche startet." + }, + "fail": { + "message": "Fehlgeschlagen" + }, + "successSlotFound": { + "message": "Termin gefunden", + "description": "Log Nachricht wenn erfolgreich ein Termin gefunden wurde." + }, + "notificationTitleSlotFound": { + "message": "Ein Impftermin ist verfügbar!", + "description": "Notification Titel wenn ein Impftermin verfügbar ist." + }, + "notificationBodySlotFound": { + "message": "Klicken Sie hier um Ihre Reservierung bei \"$VACCINATIONCENTER$\" abzuschließen.", + "description": "Notification Nachricht wenn ein Impftermin verfügbar ist.", + "placeholders": { + "vaccinationcenter": { + "content": "$1", + "example": "Centre de vaccination de la Réunion" + } + } + }, + "notificationTitleSlotBooked": { + "message": "Ihr Impftermin wurde gebucht!", + "description": "Notification Titel wenn ein Impftermin gebucht wurde." + }, + "notificationBodySlotBooked": { + "message": "Sie haben einen Termin bei \"$VACCINATIONCENTER$\".", + "description": "Notification Nachricht wenn ein Impftermin gebucht wurde.", + "placeholders": { + "vaccinationcenter": { + "content": "$1", + "example": "Centre de vaccination de la Réunion" + } + } + }, + "extensionStartMessage": { + "message": "Starte Extension mit $NUMBER$ Testzentren", + "description": "Log Nachricht wenn die Extension startet", + "placeholders": { + "number": { + "content": "$1", + "example": "1" + } + } + } +} diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json new file mode 100644 index 0000000..ba30b22 --- /dev/null +++ b/_locales/fr/messages.json @@ -0,0 +1,247 @@ +{ + "extensionName": { + "message": "vaccin.click", + "description": "Nom de l'extension." + }, + "extensionDescription": { + "message": "Trouvez et réservez automatiquement votre créneau de vaccination COVID-19.", + "description": "Description de l'extension." + }, + "extensionShortDescription": { + "message": "mon vaccin COVID-19 en 1 click !", + "description": "Description courte de l'extension." + }, + "resumeScan": { + "message": "Reprendre la surveillance des RDV", + "description": "Text du bouton pour reprendre la surveillance des RDV." + }, + "pauseScan": { + "message": "Mettre en pause la surveillance des RDV", + "description": "Text du bouton pour mettre en pause la surveillance des RDV." + }, + "firstAndSecondInjection": { + "message": "Première et deuxième dose", + "description": "Text qui décrit une première injection avec une dose de rappel." + }, + "firstInjection": { + "message": "Première dose (sans rappel)", + "description": "Text qui décrit une première injection sans dose de rappel." + }, + "secondInjection": { + "message": "Deuxième dose", + "description": "Text qui décrit une deuxième injection sans dose de rappel." + }, + "additionalInjection": { + "message": "Troisième dose", + "description": "Text qui décrit une injection de rappel au dela de la deuxième dose." + }, + "modernaVaccine": { + "message": "Vaccin Moderna", + "description": "Text qui décrit un vaccin Moderna." + }, + "pfizerVaccine": { + "message": "Vaccin Pfizer", + "description": "Text qui décrit un vaccin Pfizer." + }, + "disableAutoBook": { + "message": "Ouvrir un onglet lorsqu'une réservation est disponible", + "description": "Text qui décrit la fonctionalité lorsque la réservation automatique est désactivé." + }, + "enableAutoBook": { + "message": "Réserver automatiquement (vous devez être connecté à Doctolib)", + "description": "Text qui décrit la fonctionalité lorsque la réservation automatique est activé." + }, + "myVaccinationCenters": { + "message": "Mes centres de vaccination en réservation automatique", + "description": "Text qui décrit la liste des centres de vaccination choisis." + }, + "findVaccinationCenters": { + "message": "Trouver des centres de vaccination sur Doctolib", + "description": "Text qui décrit la fonctionalité de recherche de centre de vaccination." + }, + "shareOnTwitter": { + "message": "Partager vaccin.click sur Twitter", + "description": "Text qui décrit la fonctionalité de partage sur Twitter." + }, + "advancedConfiguration": { + "message": "Options avancées", + "description": "Text qui décrit la fonctionalité de configuration avancée." + }, + "resetEverything": { + "message": "Remise à zéro (effacera toutes les données)", + "description": "Text qui décrit la fonctionalité de réinitialisation." + }, + "activityLog": { + "message": "Journal d'activité", + "description": "Text qui décrit la fonctionalité de journal d'activité." + }, + "addToMyList": { + "message": "Ajouter à ma liste", + "description": "Text qui décrit la fonctionalité d'ajout à ma liste." + }, + "removeFromMyList": { + "message": "Retirer de ma liste", + "description": "Text qui décrit la fonctionalité de suppression de ma liste." + }, + "alertWatchlistSizeExceeded": { + "message": "Pour ne pas trop charger les serveurs de Doctolib, il n'est pas possible de surveiller plus de 24 centres en même temps. Supprimez des centres de votre liste pour en ajouter d'autres.", + "description": "Alerte quand trop de centres de vaccination sont surveillés." + }, + "clearOutdatedLocations": { + "message": "Suppression des vieux status", + "description": "Message log quand on supprime les vieux status de recherche." + }, + "selectorTimeout": { + "message": "Le sélecteur \"$SELECTOR$\" n'a pas été trouvé après 5 secondes. Ce n'est pas forcément un bug.", + "description": "Message log quand le temps d'attente pour un sélecteur est dépassé.", + "placeholders": { + "selector": { + "content": "$1", + "example": ".some-css-class" + } + } + }, + "waitForElementToBeRemovedNoElement": { + "message": "L'élement demandé pour waitForElementToBeRemoved était déjà absent avant de commencer ! L'élément doit exister.", + "description": "Message log quand le script attend pour supprimer un élément qui n'existe pas." + }, + "waitForElementToBeRemovedTimeout": { + "message": "L'élement demandé n'a pas disparu au bout de 5 secondes", + "description": "Message log quand un élément n'a pas disparu au bout de 5 secondes." + }, + "answerNoForPreviousPatientButtonNotFound": { + "message": "N'a pas pu répondre 'Non' à la question de nouveau patient", + "description": "Message log quand le script ne peut pas automatiquement répondre 'Non' à la question de nouveau patient." + }, + "chooseSpecialityOptionNotFound": { + "message": "Spécialité non trouvée. Spécialités disponibles : $SPECIALITIES$", + "description": "Message log quand le script ne sait pas choisir une spécialité.", + "placeholders": { + "specialities": { + "content": "$1", + "example": "Cardiologue, Dentiste, Médecin généraliste, Médecin spécialiste, Pédiatre, Psychiatre, Urologue" + } + } + }, + "checkAvailabilityStarted": { + "message": "Vérification de $URL$", + "description": "Message log quand le script commence la vérification d'un centre de vaccination.", + "placeholders": { + "url": { + "content": "$1", + "example": "https://www.doctolib.fr/vaccination-covid-19/centre-vaccination-covid-19-paris-75-9-avenue-de-la-reunion-75016" + } + } + }, + "chooseMotiveCategoryOptionNotFound": { + "message": "Catégorie de motif non trouvé. Motifs disponibles : $CATEGORIES$", + "description": "Message log quand le script ne sait pas choisir une catégorie de motif.", + "placeholders": { + "categories": { + "content": "$1", + "example": "Consultation, Examen, Hospitalisation, Traitement" + } + } + }, + "injectionNotFound": { + "message": "Injection ARNm non disponible $NUMBER$", + "description": "Message log quand le script ne trouve pas d'injection ARNm.", + "placeholders": { + "number": { + "content": "$1", + "example": "1" + } + } + }, + "noSlot": { + "message": "Aucun créneau disponible $NUMBER$", + "description": "Message log quand le script ne trouve pas de slot disponible.", + "placeholders": { + "number": { + "content": "$1", + "example": "1" + } + } + }, + "slotDateFormatNotFound": { + "message": "Impossible de cliquer sur le slot avec le titre $TITLE$", + "description": "Message log quand le script ne peut pas parser une date lors la selection d'un slot.", + "placeholders": { + "title": { + "content": "$1", + "example": "Mardi, 14 juin 2020" + } + } + }, + "noSecondSlot": { + "message": "Aucun créneau disponible pour le second rendez-vous $NUMBER$", + "description": "Message log quand le script ne trouve pas de slot disponible pour le second rendez-vous.", + "placeholders": { + "number": { + "content": "$1", + "example": "1" + } + } + }, + "popupConfirmationNotFound": { + "message": "Impossible de trouver le bouton pour confirmer le dialogue 'à lire'.", + "description": "Message log quand le script ne peut pas automatiquement valider le dialogue 'à lire'." + }, + "manualConfirmationRequired": { + "message": "Confirmation manuelle du RDV nécessaire", + "description": "Message log quand le script ne peut pas terminer la réservation automatique." + }, + "locationCheckInProgress": { + "message": "En cours", + "description": "Message log quand le script est en cours de vérification d'un centre de vaccination." + }, + "locationCheckStarted": { + "message": "Début de la vérification", + "description": "Message log quand le script commence la vérification d'un centre de vaccination." + }, + "fail": { + "message": "Echec" + }, + "successSlotFound": { + "message": "Succès - Créneau trouvé", + "description": "Message log quand le script trouve un slot disponible." + }, + "notificationTitleSlotFound": { + "message": "Un créneau de vaccination est disponible !", + "description": "Titre de la notification quand le script trouve un slot disponible." + }, + "notificationBodySlotFound": { + "message": "Cliquez ici pour finaliser la réservation dans le centre \"$VACCINATIONCENTER$\"", + "description": "Message de la notification quand le script trouve un slot disponible.", + "placeholders": { + "vaccinationcenter": { + "content": "$1", + "example": "Centre de vaccination de la Réunion" + } + } + }, + "notificationTitleSlotBooked": { + "message": "Votre créneau de vaccination a été réservé !", + "description": "Titre de la notification quand le script réserve un slot." + }, + "notificationBodySlotBooked": { + "message": "Vous avez rendez-vous au centre \"$VACCINATIONCENTER$\".", + "description": "Message de la notification quand le script réserve un slot.", + "placeholders": { + "vaccinationcenter": { + "content": "$1", + "example": "Centre de vaccination de la Réunion" + } + } + }, + "extensionStartMessage": { + "message": "Démarrage de l'extension avec $NUMBER$ centres à traiter", + "description": "Message log quand le script démarre l'extension.", + "placeholders": { + "number": { + "content": "$1", + "example": "1" + } + } + } +} diff --git a/background_scripts/index.js b/background_scripts/index.js index b117180..ad7b94f 100644 --- a/background_scripts/index.js +++ b/background_scripts/index.js @@ -3,10 +3,14 @@ const appStatus = new AppStatus(); const vCLStorage = new VCLocalStorage(); const jobs = new JobQueue(10000, 45000, (job) => { - vCLStorage.setLocationStatus(job, LocationCheckStatus.WORKING, "En cours"); + vCLStorage.setLocationStatus( + job, + LocationCheckStatus.WORKING, + browser.i18n.getMessage("locationCheckInProgress") + ); vCLStorage.locationLog( appStatus.getLocation(job), - "Début de la vérification" + browser.i18n.getMessage("locationCheckStarted") ); // Prévoir le job suivant @@ -44,7 +48,10 @@ LocationCheckStatus.ERROR, data.error.message ); - vCLStorage.locationLog(data.location, "Echec - " + data.error.message); + vCLStorage.locationLog( + data.location, + browser.i18n.getMessage("fail") + " - " + data.error.message + ); break; case "found": @@ -53,7 +60,10 @@ LocationCheckStatus.SUCCESS, "Créneau trouvé" ); - vCLStorage.locationLog(data.location, "Succès - Créneau trouvé"); + vCLStorage.locationLog( + data.location, + browser.i18n.getMessage("successSlotFound") + ); const tabs = await browser.tabs.query({ url: data.url }); @@ -65,8 +75,11 @@ await browser.notifications.create(data.url, { type: "basic", iconUrl: browser.runtime.getURL("icons/vaccine-color.svg"), - title: "Un créneau de vaccination est disponible !", - message: `Cliquez ici pour finaliser la réservation dans le centre "${data.location.name}"`, + title: browser.i18n.getMessage("notificationTitleSlotFound"), + message: browser.i18n.getMessage( + "notificationBodySlotFound", + data.location.name + ), priority: 2, }); break; @@ -87,8 +100,11 @@ await browser.notifications.create({ type: "basic", iconUrl: browser.runtime.getURL("icons/vaccine-color.svg"), - title: "Votre créneau de vaccination a été réservé !", - message: `Vous avez rendez-vous au centre "${data.location.name}".`, + title: browser.i18n.getMessage("notificationTitleSlotBooked"), + message: browser.i18n.getMessage( + "notificationBodySlotBooked", + data.location.name + ), }); break; } @@ -99,7 +115,7 @@ // Executer les jobs vCLStorage.log( - `Démarrage de l'extension avec ${jobs.jobs.length} centres à traiter` + browser.i18n.getMessage("extensionStartMessage", jobs.jobs.length) ); jobs.start(); vCLStorage.startCheckLocations(); diff --git a/browser_action/index.html b/browser_action/index.html index 34a4308..3af5c50 100644 --- a/browser_action/index.html +++ b/browser_action/index.html @@ -14,17 +14,22 @@
- vaccin.click : mon - vaccin COVID-19 en 1 click ! + vaccin.click + : + mon vaccin COVID-19 en 1 click !
- -
@@ -39,22 +44,30 @@ id="fullServiceInjection" checked /> - +
- +
- +
- +
@@ -68,11 +81,15 @@ id="pfizerInjection" checked /> - +
- +
@@ -81,14 +98,14 @@
-
-