diff --git a/src/CNIRevelator.py b/src/CNIRevelator.py
index 3fe7fb0..d332afe 100644
--- a/src/CNIRevelator.py
+++ b/src/CNIRevelator.py
@@ -28,14 +28,17 @@ import sys
import os
import subprocess
import threading
-import traceback
import psutil
+from tkinter import *
+from tkinter.messagebox import *
import launcher # launcher.py"
import updater # updater.py
import globs # globs.py
import pytesseract # pytesseract.py
import logger # logger.py
+import lang # lang.py
+import ihm # ihm.py
from main import * # main.py
@@ -59,15 +62,15 @@ def main():
text = 'Tesseract version ' + str(tesser_version) + ' Licensed Apache 2004 successfully initiated\n'
mainw.logOnTerm(text)
- mainw.logOnTerm('\n\nEntrez la première ligne de MRZ svp \n')
+ mainw.logOnTerm('\n\n{} \n'.format(lang.all[globs.CNIRlang]["Please type a MRZ or open a scan"]))
if globs.CNIRNewVersion:
- showinfo('Changelog : résumé de mise à jour', ('Version du logiciel : CNIRevelator ' + globs.verstring_full + '\n\n' + globs.changelog), parent=mainw)
+ showinfo("Changelog : update summary", ('{} : CNIRevelator {}\n\n{}'.format(lang.all[globs.CNIRlang]["Program version"], globs.verstring_full, globs.changelog)), parent=mainw)
logfile.printdbg('main() : **** Launching App_main() ****')
try:
mainw.mainloop()
except Exception as e:
- showerror("CNIRevelator Fatal Error", "An error has occured : {}".format(e), parent=mainw)
+ showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Error"], "{} : {}".format(lang.all[globs.CNIRlang]["An error has occured"],e), parent=mainw)
logfile.printdbg('main() : **** Ending App_main() ****')
logfile.printdbg('*** CNIRevelator LOGFILE. Goodbye World ! ***')
@@ -76,15 +79,36 @@ def main():
## BOOTSTRAP OF CNIREVELATOR
+
+# LANGUAGE
+if os.path.isfile(globs.CNIRLangFile):
+ with open(globs.CNIRLangFile, 'r') as (configFile):
+ try:
+ # Reading it
+ globs.CNIRlang = configFile.read()
+ except Exception as e:
+ ihm.crashCNIR()
+ raise IOError(str(e))
+else:
+ with open(globs.CNIRLangFile, 'w') as (configFile):
+ try:
+ # Writing it
+ configFile.write(globs.CNIRlang)
+ except Exception as e:
+ ihm.crashCNIR()
+ raise IOError(str(e))
+
+# GO
try:
launcherThread = threading.Thread(target=updater.umain, daemon=False)
launcher.lmain(launcherThread)
except Exception:
+ ihm.crashCNIR()
updater.exitProcess(1)
if updater.UPDATE_IS_MADE:
# Launch app !
- args = updater.UPATH + '\\CNIRevelator.exe ' + globs.CNIRFolder
+ args = updater.UPATH + '\\CNIRevelator.exe' + " DELETE " + globs.CNIRFolder
cd = updater.UPATH
for i in range(0,3):
try:
@@ -99,6 +123,6 @@ if updater.UPDATE_IS_MADE:
try:
main()
except Exception as e:
- traceback.print_exc(file=sys.stdout)
+ ihm.crashCNIR()
updater.exitProcess(0)
\ No newline at end of file
diff --git a/src/downloader.py b/src/downloader.py
index c10a7e2..a72c8f8 100644
--- a/src/downloader.py
+++ b/src/downloader.py
@@ -35,6 +35,7 @@ from time import time
import logger # logger.py
import globs # globs.py
import ihm # ihm.py
+import lang # lang.py
class AESCipher(object):
@@ -184,8 +185,8 @@ class newdownload:
reducedFilename = filename.split("\\")[-1]
- launcherWindow.printmsg('Downloading {}'.format(title))
- logfile.printdbg('Requesting download of {}'.format(reducedFilename))
+ launcherWindow.printmsg('{} {}'.format(lang.all[globs.CNIRlang]["Downloading"], title))
+ logfile.printdbg('{} {}'.format("Downloading", reducedFilename))
try:
os.remove(filename)
@@ -201,12 +202,12 @@ class newdownload:
launcherWindow.progressBar.stop()
launcherWindow.progressBar.configure(mode='determinate', value=(int(Percent)), maximum=100)
- launcherWindow.printmsg('Downloading {}'.format(title) + ' : {:4.2f} %'.format(Percent))
+ launcherWindow.printmsg('{} {}'.format(lang.all[globs.CNIRlang]["Downloading"], title) + ' : {:4.2f} %'.format(Percent))
launcherWindow.progressBar.configure(mode='indeterminate', value=0, maximum=20)
launcherWindow.progressBar.start()
- logfile.printdbg('Successful retrieved {}'.format(filename))
+ logfile.printdbg('{} {}'.format(lang.all[globs.CNIRlang]["Successful retrieved"], filename))
return filename
diff --git a/src/globs.py b/src/globs.py
index 42b1e6c..e183884 100644
--- a/src/globs.py
+++ b/src/globs.py
@@ -31,7 +31,7 @@ verstring_full = "{}.{}.{} {}".format(version[0], version[1], version[2], v
verstring = "{}.{}".format(version[0], version[1])
debug = True
-changelog = "Version 3.1.0 \nMise-à-jour majeure avec les progressions suivantes :\n- Modifications cosmétiques de l'interface utilisateur\n- Stabilisation des changements effectués sur la version mineure 3.0 : interface utilisateur, OCR, VISA A et B, logging"
+changelog = "Version 3.1.0 \nMise-à-jour majeure avec les progressions suivantes :\n- Modifications cosmétiques de l'interface utilisateur\n- Stabilisation des changements effectués sur la version mineure 3.0 : interface utilisateur, OCR, VISA A et B, logging\n- Rationalisation du système de langues"
CNIRTesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
CNIRFolder = os.getcwd()
@@ -39,6 +39,8 @@ CNIRLColor = "#006699"
CNIRName = "CNIRevelator {}".format(verstring)
CNIRCryptoKey = '82Xh!efX3#@P~2eG'
CNIRNewVersion = False
+CNIRLangFile = CNIRFolder + '\\config\\lang.ig'
+CNIRlang = "fr"
CNIRConfig = CNIRFolder + '\\config\\conf.ig'
CNIRTesser = CNIRFolder + '\\Tesseract-OCR4\\'
@@ -47,3 +49,5 @@ CNIRMainLog = CNIRFolder + '\\logs\\main.log'
CNIRUrlConfig = CNIRFolder + '\\config\\urlconf.ig'
CNIRVerStock = CNIRFolder + '\\downloads\\versions.lst'
CNIREnv = CNIRFolder + '\\Data\\'
+
+CNIROpenFile = True
\ No newline at end of file
diff --git a/src/ihm.py b/src/ihm.py
index 9c7622c..6759960 100644
--- a/src/ihm.py
+++ b/src/ihm.py
@@ -24,14 +24,17 @@
"""
from tkinter import *
+import webbrowser
from tkinter.messagebox import *
from tkinter import filedialog
from tkinter import ttk
import cv2
import PIL.Image, PIL.ImageTk
+import traceback
import logger # logger.py
import globs # globs.py
+import lang # lang.py
controlKeys = ["Escape", "Right", "Left", "Up", "Down", "Home", "End", "BackSpace", "Delete", "Inser", "Shift_L", "Shift_R", "Control_R", "Control_L"]
@@ -42,7 +45,7 @@ class DocumentAsk(Toplevel):
self.choice = 0
vals = [0, 1]
super().__init__(parent)
- self.title("Choisir le document d'identité :")
+ self.title("{} :".format(lang.all[globs.CNIRlang]["Choose the identity document"]))
ttk.Radiobutton(self, text=choices[0], command=self.register0, value=vals[0]).pack()
ttk.Radiobutton(self, text=choices[1], command=self.register1, value=vals[1]).pack()
@@ -68,19 +71,19 @@ class DocumentAsk(Toplevel):
self.choice = 1
def ok(self):
self.destroy()
-
-
+
+
class OpenScanDialog(Toplevel):
def __init__(self, parent, text):
super().__init__(parent)
self.parent = parent
- self.title('Validation de la MRZ détectée par OCR')
+ self.title(lang.all[globs.CNIRlang]["OCR Detection Validation"])
self.resizable(width=False, height=False)
self.termtext = Text(self, state='normal', width=45, height=2, wrap='none', font='Terminal 17', fg='#121f38')
self.termtext.grid(column=0, row=0, sticky='NEW', padx=5, pady=5)
self.termtext.insert('end', text + '\n')
- self.button = Button(self, text='Valider', command=(self.valid))
+ self.button = Button(self, text=lang.all[globs.CNIRlang]["Validate"], command=(self.valid))
self.button.grid(column=0, row=1, sticky='S', padx=5, pady=5)
self.update()
hs = self.winfo_screenheight()
@@ -102,27 +105,27 @@ class OpenScanDialog(Toplevel):
for i in range(len(texting)):
for char in texting[i]:
if char not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789<':
- showerror('Erreur de validation', 'La MRZ soumise contient des caractères invalides', parent=self)
+ showerror(lang.all[globs.CNIRlang]["Validation Error"], lang.all[globs.CNIRlang]["The submitted MRZ contains invalid characters"], parent=self)
self.parent.validatedtext = ''
self.destroy()
-
+
class LoginDialog(Toplevel):
def __init__(self, parent):
self.key = ''
self.login = ''
super().__init__(parent)
- self.title('Connexion')
+ self.title(lang.all[globs.CNIRlang]["Connection"])
Label(self, text='IPN : ').pack()
self.entry_login = Entry(self)
self.entry_login.insert(0, '')
self.entry_login.pack()
- Label(self, text='Mot de passe : ').pack()
+ Label(self, text='{} : '.format(lang.all[globs.CNIRlang]["Password"])).pack()
self.entry_pass = Entry(self, show='*')
self.entry_pass.insert(0, '')
self.entry_pass.pack()
- Button(self, text='Connexion', command=(self.connecti)).pack()
+ Button(self, text=lang.all[globs.CNIRlang]["Connection"], command=(self.connecti)).pack()
self.resizable(width=False, height=False)
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
@@ -185,7 +188,7 @@ class LauncherWindow(Tk):
self.mainCanvas.create_text((wwidth / 2), (wheight / 3), text=(globs.CNIRName), font='Helvetica 30', fill='white')
self.mainCanvas.create_text((wwidth / 2), (wheight / 2), text="version " + (globs.verstring_full), font='Helvetica 8', fill='white')
- self.msg = self.mainCanvas.create_text((wwidth / 2), (wheight / 1.20), text='Booting up...', font='Helvetica 9', fill='white')
+ self.msg = self.mainCanvas.create_text((wwidth / 2), (wheight / 1.20), text=lang.all[globs.CNIRlang]["Booting up..."], font='Helvetica 9', fill='white')
#self.pBarZone = Frame(self.mainCanvas, width=wwidth, height=wheight/10)
self.update()
@@ -205,7 +208,8 @@ class LauncherWindow(Tk):
self.iconbitmap('id-card.ico')
logfile = logger.logCur
logfile.printdbg('Launcher IHM successful')
- self.protocol('WM_DELETE_WINDOW', lambda : self.destroy())
+ self.protocol('WM_DELETE_WINDOW', lambda : 0)
+ self.attributes("-topmost", 1)
self.update()
@@ -230,7 +234,24 @@ class ResizeableCanvas(Canvas):
self.height = event.height
# rescale all the objects tagged with the "all" tag
self.scale("all",0,0,wscale,hscale)
-
+
+def crashCNIR():
+ """
+ last solution
+ """
+ # Global handler
+ logfile = logger.logCur
+ # hide main window
+ root = Tk()
+ root.withdraw()
+ logfile.printerr("FATAL ERROR : see traceback below.\n{}".format(traceback.format_exc()))
+ showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["CNIRevelator crashed because a fatal error occured. View log for more infos and please open an issue on Github"])
+ res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to open an issue on Github to report this bug ?"])
+ if res == "yes":
+ webbrowser.open_new("https://github.com/neox95/CNIRevelator/issues")
+ root.destroy()
+
+
## Global Handler
launcherWindowCur = LauncherWindow()
diff --git a/src/lang.py b/src/lang.py
new file mode 100644
index 0000000..100706c
--- /dev/null
+++ b/src/lang.py
@@ -0,0 +1,299 @@
+"""
+********************************************************************************
+* CNIRevelator *
+* *
+* Desc: Application langage file *
+* *
+* Copyright © 2018-2019 Adrien Bourmault (neox95) *
+* *
+* This file is part of CNIRevelator. *
+* *
+* CNIRevelator is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation, either version 3 of the License, or *
+* any later version. *
+* *
+* CNIRevelator is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY*without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with CNIRevelator. If not, see . *
+********************************************************************************
+"""
+
+import globs # globs.py
+
+## FRENCH LANGUAGE
+french = \
+{
+"Please type a MRZ or open a scan" : "Veuillez taper une MRZ ou ouvrir un scan svp",
+"Changelog : update summary" : "Changelog : résumé de mise à jour",
+"Program version" : "Version du logiciel",
+"CNIRevelator Fatal Error" : "Erreur fatale de CNIRevelator",
+"An error has occured" : "Une erreur s'est produite",
+"Downloading" : "Téléchargement de",
+"Successful retrieved" : "Réussite du téléchargement de",
+"Choose the identity document" : "Choisir le document d'identité",
+"OCR Detection Validation" : "Validation de la MRZ détectée par OCR",
+"Validate" : "Valider",
+"Validation Error" : "Erreur de validation",
+"The submitted MRZ contains invalid "
+ "characters" : "La MRZ soumise contient des caractères invalides",
+"Connection" : "Connexion",
+"Password" : "Mot de passe",
+"Booting up..." : "Démarrage",
+"CNIRevelator Fatal Eror" : "Erreur Fatale de CNIRevelator",
+"CNIRevelator crashed because a "
+"fatal error occured. View log for "
+"more infos and please open "
+"an issue on Github" : "CNIRevelator s'est arrêté car une erreur fatale s'est produite. Consultez le journal pour plus d'informations et ouvrez s'il vous plaît un ticket sur Github.",
+"Would you like to open an issue "
+"on Github to report this bug ?" : "Souhaitez-vous ouvrir un ticket sur Github pour signaler ce bogue?",
+"Starting..." : "Lancement...",
+"Informations about the current "
+"document" : "Informations sur la pièce d'identité",
+"IDLE" : "EN ATTENTE",
+"Status" : "Statut",
+"Name" : "Nom",
+"Birth date" : "Date de naissance",
+"Issue date" : "Date de délivrance",
+"Expiration date" : "Date d'expiration",
+"Sex" : "Sexe",
+"Issuing country" : "Pays émetteur",
+"Nationality" : "Nationalité",
+"Registration" : "Immatriculation",
+"Document number" : "Numéro de document",
+"Unknown" : "Inconnu(e)",
+"Display and processing of "
+"documents" : "Affichage et traitement de documents",
+"Complete MRZ capture terminal" : "Terminal de saisie de MRZ complète",
+"Quick entry terminal (731)" : "Terminal de saisie rapide (731)",
+"Monitor" : "Moniteur",
+"New" : "Nouveau",
+"Open scan..." : "Ouvrir scan...",
+"Quit" : "Quitter",
+"File" : "Fichier",
+"Keyboard commands" : "Commandes au clavier",
+"Report a bug" : "Signaler un problème",
+"About CNIRevelator" : "A propos de CNIRevelator",
+"Help" : "Aide",
+"OCR module error" : "Erreur du module OCR",
+"The OCR module located at {} "
+"can not be found or corrupted. "
+"It will be reinstalled at "
+"the next run" : "Le module OCR localisé en {} est introuvable ou corrompu. Il sera réinstallé à la prochaine exécution",
+"The Tesseract module "
+"encountered a problem: {}" : "Le module Tesseract a rencontré un problème : {}",
+"Tesseract error : {}. "
+"Will be reinstallated" : "Erreur de Tesseract : {}. Le module sera réinstallé",
+"Document detected: {}\n" : "Document detecté : {}\n",
+"Document detected again: {}\n" : "Document re-detecté : {}\n",
+"Character not accepted !\n" : "Caractère non accepté !\n",
+"Open a scan of document..." : "Ouvrir un scan de document...",
+"OpenCV error (image processing)" : "Erreur OpenCV (traitement d'images)",
+"A critical error has occurred in "
+"the OpenCV image processing "
+"manager used by CNIRevelator, the "
+"application will reset itself" : "Une erreur critique s'est produite dans le gestionnaire de traitement d'images OpenCV utilisé par CNIRevelator. L'application va se réinitialiser",
+"ABOUT" : 'Version du logiciel : CNIRevelator ' + globs.verstring_full + '\n\n'
+ "Copyright © 2018-2019 Adrien Bourmault (neox95)" + "\n\n"
+ "CNIRevelator est un logiciel libre : vous avez le droit de le modifier et/ou le distribuer "
+ "dans les termes de la GNU General Public License telle que publiée par "
+ "la Free Software Foundation, dans sa version 3 ou "
+ "ultérieure. " + "\n\n"
+ "CNIRevelator est distribué dans l'espoir d'être utile, sans toutefois "
+ "impliquer une quelconque garantie de "
+ "QUALITÉ MARCHANDE ou APTITUDE À UN USAGE PARTICULIER. Référez vous à la "
+ "GNU General Public License pour plus de détails à ce sujet. "
+ "\n\n"
+ "Vous devriez avoir reçu une copie de la GNU General Public License "
+ "avec CNIRevelator. Si cela n'est pas le cas, jetez un oeil à . "
+ "\n\n"
+ "Le module d'OCR Tesseract 4.0 est soumis à l'Apache License 2004."
+ "\n\n"
+ "Les bibliothèques python et l'environnement Anaconda 3 sont soumis à la licence BSD 2018-2019."
+ "\n\n"
+ "Le code source de ce programme est disponible sur Github à l'adresse .\n"
+ "Son fonctionnement est conforme aux normes et directives du document 9303 de l'OACI régissant les documents de voyages et d'identité." + '\n\n'
+ " En cas de problèmes ou demande particulière, ouvrez-y une issue ou bien envoyez un mail à neox@os-k.eu !\n\n",
+
+"KEYBHELP" : "Terminal de saisie rapide (731) : \n\n"
+ "Caractères autorisés : Alphanumériques en majuscule et le caractère '<'. Pas de minuscules ni caractères spéciaux, autrement la somme est mise à zéro \n\n"
+ "Calculer résultat :\t\t\tTouche Ctrl droite \n"
+ "Copier :\t\t\t\tCtrl-C \n"
+ "Coller :\t\t\t\tCtrl-V \n"
+ "\n\n"
+ "Terminal de saisie MRZ complète : \n\n"
+ "Caractères autorisés : Alphanumériques en majuscule et le caractère '<'. Pas de minuscules ni caractères spéciaux, autrement la somme est mise à zéro \n\n"
+ "Calculer résultat :\t\t\tTouche Ctrl droite \n"
+ "Compléter champ :\t\t\tTouche Tab \n"
+ "Copier :\t\t\t\tCtrl-C \n"
+ "Coller :\t\t\t\tCtrl-V \n"
+ "Forcer une nouvelle détection du document :\tEchap\n",
+"Document Review: {}\n\n" : "Examen du document : {}\n\n",
+"Check sum position {}: Lu {} VS "
+"Calculated {} and {}\n" : "Check sum position {}: Lu {} VS Calculated {} and {}\n",
+"COMPLIANT" : "CONFORME",
+"IMPROPER" : "NON CONFORME",
+"Installing the updates" : "Installation des mises-à-jour",
+"Verifying download..." : "Vérification du téléchargement ...",
+"Preparing installation..." : "Préparation de l'installation",
+"Success !" : "Installation terminée !",
+"Launching the new version..." : "Lancement de la nouvelle version...",
+"Credentials Error. No effective "
+"update !" : "Identifiants incorrects. Pas de mise-à-jour !",
+"Deleting old version" : "Suppression de l'ancienne version",
+'Software is up-to-date !' : "Logiciel à jour !",
+"An error occured. "
+"No effective update !" : "Une erreur s'est produite. Pas de mise-à-jour !",
+"Shortcut creation" : "Création de raccourci",
+"Would you like to create/update "
+"the shortcut for CNIRevelator "
+"on your desktop ?" : "Souhaitez vous créer/mettre à jour le raccourci pour CNIRevelator sur votre bureau ?",
+"The file you provided is "
+"not found : {}" : "Fichier transmis non trouvé : {}"
+}
+
+## ENGLISH LANGUAGE
+
+english = \
+{
+"Please type a MRZ or open a scan" : "Please type a MRZ or open a scan",
+"Changelog : update summary" : "Changelog : update summary",
+"Program version" : "Program version",
+"CNIRevelator Fatal Error" : "CNIRevelator Fatal Error" ,
+"An error has occured" : "An error has occured",
+"Downloading" : "Downloading",
+"Successful retrieved" : "Successful retrieved",
+"Choose the identity document" : "Choose the identity document" ,
+"OCR Detection Validation" : "OCR Detection Validation",
+"Validate" : "Validate",
+"Validation Error" : "Validation Error",
+"The submitted MRZ contains invalid "
+ "characters" : "The submitted MRZ contains invalid characters",
+"Connection" : "Connection",
+"Password" : "Password",
+"Booting up..." : "Booting up...",
+"CNIRevelator Fatal Eror" : "CNIRevelator Fatal Eror",
+"CNIRevelator crashed because a "
+"fatal error occured. View log for "
+"more infos and please open "
+"an issue on Github" : "CNIRevelator crashed because a fatal error occured. View log for more infos and please open an issue on Github",
+"Would you like to open an issue "
+"on Github to report this bug ?" : "Would you like to open an issue on Github to report this bug ?",
+"Starting..." : "Starting...",
+"Informations about the current "
+"document" : "Informations about the current document",
+"IDLE" : "IDLE",
+"Status" : "Status",
+"Name" : "Name",
+"Birth date" : "Birth date",
+"Issue date" : "Date de délivrance",
+"Expiration date" : "Issue date",
+"Sex" : "Sex",
+"Issuing country" : "Issuing country",
+"Nationality" : "Nationality",
+"Registration" : "Registration",
+"Document number" : "Document number",
+"Unknown" : "Unknown",
+"Display and processing of "
+"documents" : "Display and processing of documents",
+"Complete MRZ capture terminal" : "Complete MRZ capture terminal",
+"Quick entry terminal (731)" : "Quick entry terminal (731)",
+"Monitor" : "Monitor",
+"New" : "New",
+"Open scan..." : "Open scan...",
+"Quit" : "Quit",
+"File" : "File",
+"Keyboard commands" : "Keyboard commands",
+"Report a bug" : "Report a bug",
+"About CNIRevelator" : "About CNIRevelator",
+"Help" : "Help",
+"OCR module error" : "OCR module error",
+"The OCR module located at {} "
+"can not be found or corrupted. "
+"It will be reinstalled at "
+"the next run" : "The OCR module located at {} can not be found or corrupted. It will be reinstalled at the next run",
+"The Tesseract module "
+"encountered a problem: {}" : "The Tesseract module encountered a problem: {}",
+"Tesseract error : {}. "
+"Will be reinstallated" : "Tesseract error : {}. Will be reinstallated",
+"Document detected: {}\n" : "Document detected : {}\n",
+"Document detected again: {}\n" : "Document detected again : {}\n",
+"Character not accepted !\n" : "Character not accepted !\n",
+"Open a scan of document..." : "Open a scan of document...",
+"OpenCV error (image processing)" : "OpenCV error (image processing)",
+"A critical error has occurred in "
+"the OpenCV image processing "
+"manager used by CNIRevelator, the "
+"application will reset itself" : "A critical error has occurred in the OpenCV image processing manager used by CNIRevelator, the application will reset itself",
+
+"ABOUT" : 'Software Version: CNIRevelator' + globs.verstring_full + '\n\n'
+ "Copyright © 2018-2019 Adrien Bourmault (neox95)" + "\n\n"
+ "CNIRevelator is free software: you have the right to modify and / or distribute it"
+ "in the terms of the GNU General Public License as published by"
+ "Free Software Foundation, version 3 or"
+ "later." + "\n\n"
+ "CNIRevelator is distributed in the hope of being useful, without however"
+ "imply any guarantee of"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE Refer to the"
+ "GNU General Public License for more details about this."
+ "\n\n"
+ "You should have received a copy of the GNU General Public License"
+ "with CNIRevelator, if this is not the case, take a look at ."
+ "\n\n"
+ "The Tesseract 4.0 OCR module is subject to the 2004 Apache License."
+ "\n\n"
+ "Python libraries and the Anaconda 3 environment are subject to the BSD 2018-2019 license."
+ "\n\n"
+ "The source code for this program is available on Github at . \n"
+ "Its operation is in accordance with the standards and guidelines of ICAO document 9303 governing travel and identity documents." + '\n\n'
+ "In case of problems or special request, open an issue or send an email to neox@os-k.eu! \n\n",
+
+
+"KEYBHELP" : "Fast entry terminal (731): \n\n"
+ "Allowed characters: Alphanumeric uppercase and the character '<' No lowercase or special characters, otherwise the sum is set to zero \n\n"
+ "Calculate Result:\t\t\tControl Right\n"
+ "Copy:\t\t\t\tCtrl-C\n"
+ "Paste:\t\t\t\tCtrl-V\n"
+ "\n\n"
+ "MRZ input terminal complete: \n\n"
+ "Allowed characters: Alphanumeric uppercase and the character '<' No lowercase or special characters, otherwise the sum is set to zero \n\n"
+ "Calculate Result:\t\t\tControl Right\n"
+ "Complete field:\t\t\tTab button\n"
+ "Copy:\t\t\t\tCtrl-C\n"
+ "Paste:\t\t\t\tCtrl-V\n"
+ "Force a new document detection:\tEchap\n",
+
+"Document Review: {}\n\n" : "Document Review: {}\n\n",
+"Check sum position {}: Lu {} VS "
+"Calculated {} and {}\n" : "Check sum position {}: Lu {} VS Calculated {} and {}\n",
+"COMPLIANT" : "COMPLIANT",
+"IMPROPER" : "IMPROPER",
+"Installing the updates" : "Installing the updates",
+"Verifying download..." : "Verifying download...",
+"Preparing installation..." : "Preparing installation...",
+"Success !" : "Success !",
+"Launching the new version..." : "Launching the new version...",
+"Credentials Error. No effective "
+"update !" : "Credentials Error. No effective update !",
+"Deleting old version" : "Deleting old version",
+'Software is up-to-date !' : "Software is up-to-date !",
+"An error occured. "
+"No effective update !" : "An error occured. No effective update !",
+"Shortcut creation" : "Shortcut creation",
+"Would you like to create/update "
+"the shortcut for CNIRevelator on "
+"your desktop ?" : "Would you like to create/update the shortcut for CNIRevelator on your desktop ?",
+"The file you provided is not "
+"found : {}" : "The file you provided is not found : {}"
+}
+
+## MAIN DICT
+all = \
+{
+"fr" : french,
+"en" : english
+}
\ No newline at end of file
diff --git a/src/launcher.py b/src/launcher.py
index 3edcfaa..aa35b8d 100644
--- a/src/launcher.py
+++ b/src/launcher.py
@@ -26,12 +26,12 @@
import sys
import os
import threading
-import traceback
import updater # updater.py
import ihm # ihm.py
import globs # globs.py
import logger # logger.py
+import lang # lang.py
## Main function
def lmain(mainThread):
@@ -44,7 +44,7 @@ def lmain(mainThread):
# Hello user
launcherWindow.progressBar.configure(mode='indeterminate', value=0, maximum=20)
- launcherWindow.printmsg('Starting...')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]["Starting..."])
launcherWindow.progressBar.start()
# Starting the main update thread
diff --git a/src/main.py b/src/main.py
index b921838..18ec34d 100644
--- a/src/main.py
+++ b/src/main.py
@@ -32,17 +32,18 @@ from tkinter import ttk
import threading
from datetime import datetime
import re
-import traceback
import cv2
import PIL.Image, PIL.ImageTk
import os, shutil
import webbrowser
+import sys, os
import ihm # ihm.py
import logger # logger.py
import mrz # mrz.py
import globs # globs.py
import pytesseract # pytesseract.py
+import lang # lang.py
# Global handler
logfile = logger.logCur
@@ -78,7 +79,7 @@ class mainWindow(Tk):
self.grid_rowconfigure(2, weight=1, minsize=(hs / 2 * 0.35))
# Prepare the data sections
- self.lecteur_ci = ttk.Labelframe(self, text="Informations sur la pièce d'identité")
+ self.lecteur_ci = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Informations about the current document"])
self.lecteur_ci.grid_columnconfigure(0, weight=1)
self.lecteur_ci.grid_columnconfigure(1, weight=1)
self.lecteur_ci.grid_columnconfigure(2, weight=1)
@@ -92,50 +93,50 @@ class mainWindow(Tk):
self.lecteur_ci.grid_rowconfigure(5, weight=1)
# Fill the data sections
- ttk.Label((self.lecteur_ci), text='Statut : ').grid(column=0, row=0, padx=5, pady=5)
- self.STATUStxt = ttk.Label((self.lecteur_ci), text='EN ATTENTE', font=("TkDefaultFont", 13, "bold"), foreground="orange", anchor=CENTER)
+ ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Status"])).grid(column=0, row=0, padx=5, pady=5)
+ self.STATUStxt = ttk.Label((self.lecteur_ci), text=lang.all[globs.CNIRlang]["IDLE"], font=("TkDefaultFont", 13, "bold"), foreground="orange", anchor=CENTER)
self.STATUStxt.grid(column=1, row=0, padx=5, pady=5)
- ttk.Label((self.lecteur_ci), text='Nom : ').grid(column=0, row=1, padx=5, pady=5)
+ ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Name"])).grid(column=0, row=1, padx=5, pady=5)
self.nom = ttk.Label((self.lecteur_ci), text=' ')
self.nom.grid(column=1, row=1, padx=5, pady=5)
- ttk.Label((self.lecteur_ci), text='Nom (2) : ').grid(column=0, row=2, padx=5, pady=5)
+ ttk.Label((self.lecteur_ci), text='{} (2) : '.format(lang.all[globs.CNIRlang]["Name"])).grid(column=0, row=2, padx=5, pady=5)
self.prenom = ttk.Label((self.lecteur_ci), text=' ')
self.prenom.grid(column=1, row=2, padx=5, pady=5)
- ttk.Label((self.lecteur_ci), text='Date de naissance : ').grid(column=0, row=3, padx=5, pady=5)
+ ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Birth date"])).grid(column=0, row=3, padx=5, pady=5)
self.bdate = ttk.Label((self.lecteur_ci), text=' ')
self.bdate.grid(column=1, row=3, padx=5, pady=5)
- ttk.Label((self.lecteur_ci), text='Date de délivrance : ').grid(column=0, row=4, padx=5, pady=5)
+ ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Issue date"])).grid(column=0, row=4, padx=5, pady=5)
self.ddate = ttk.Label((self.lecteur_ci), text=' ')
self.ddate.grid(column=1, row=4, padx=5, pady=5)
- ttk.Label((self.lecteur_ci), text="Date d'expiration : ").grid(column=0, row=5, padx=5, pady=5)
+ ttk.Label((self.lecteur_ci), text="{} : ".format(lang.all[globs.CNIRlang]["Expiration date"])).grid(column=0, row=5, padx=5, pady=5)
self.edate = ttk.Label((self.lecteur_ci), text=' ')
self.edate.grid(column=1, row=5, padx=5, pady=5)
- ttk.Label((self.lecteur_ci), text='Sexe du porteur : ').grid(column=4, row=1, padx=5, pady=5)
+ ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Sex"])).grid(column=4, row=1, padx=5, pady=5)
self.sex = ttk.Label((self.lecteur_ci), text=' ')
self.sex.grid(column=5, row=1, padx=5, pady=5)
- ttk.Label((self.lecteur_ci), text='Pays de délivrance : ').grid(column=4, row=2, padx=5, pady=5)
+ ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Issuing country"])).grid(column=4, row=2, padx=5, pady=5)
self.pays = ttk.Label((self.lecteur_ci), text=' ')
self.pays.grid(column=5, row=2, padx=5, pady=5)
- ttk.Label((self.lecteur_ci), text='Nationalité du porteur : ').grid(column=4, row=3, padx=5, pady=5)
+ ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Nationality"])).grid(column=4, row=3, padx=5, pady=5)
self.nat = ttk.Label((self.lecteur_ci), text=' ')
self.nat.grid(column=5, row=3, padx=5, pady=5)
- ttk.Label((self.lecteur_ci), text='Immatriculation : ').grid(column=4, row=4, padx=5, pady=5)
+ ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Registration"])).grid(column=4, row=4, padx=5, pady=5)
self.indic = ttk.Label((self.lecteur_ci), text=' ')
self.indic.grid(column=5, row=4, padx=5, pady=5)
- ttk.Label((self.lecteur_ci), text='Numéro de document : ').grid(column=4, row=5, padx=5, pady=5)
+ ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Document number"])).grid(column=4, row=5, padx=5, pady=5)
self.no = ttk.Label((self.lecteur_ci), text=' ')
self.no.grid(column=5, row=5, padx=5, pady=5)
- self.nom['text'] = 'Inconnu(e)'
- self.prenom['text'] = 'Inconnu(e)'
- self.bdate['text'] = 'Inconnu(e)'
- self.ddate['text'] = 'Inconnu(e)'
- self.edate['text'] = 'Inconnu(e)'
- self.no['text'] = 'Inconnu(e)'
- self.sex['text'] = 'Inconnu(e)'
- self.nat['text'] = 'Inconnu(e)'
- self.pays['text'] = 'Inconnu(e)'
- self.indic['text'] = 'Inconnu(e)'
+ self.nom['text'] = lang.all[globs.CNIRlang]["Unknown"]
+ self.prenom['text'] = lang.all[globs.CNIRlang]["Unknown"]
+ self.bdate['text'] = lang.all[globs.CNIRlang]["Unknown"]
+ self.ddate['text'] = lang.all[globs.CNIRlang]["Unknown"]
+ self.edate['text'] = lang.all[globs.CNIRlang]["Unknown"]
+ self.no['text'] = lang.all[globs.CNIRlang]["Unknown"]
+ self.sex['text'] = lang.all[globs.CNIRlang]["Unknown"]
+ self.nat['text'] = lang.all[globs.CNIRlang]["Unknown"]
+ self.pays['text'] = lang.all[globs.CNIRlang]["Unknown"]
+ self.indic['text'] = lang.all[globs.CNIRlang]["Unknown"]
self.infoList = \
@@ -153,7 +154,7 @@ class mainWindow(Tk):
}
# The the image viewer
- self.imageViewer = ttk.Labelframe(self, text='Affichage et traitement de documents')
+ self.imageViewer = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Display and processing of documents"])
self.imageViewer.grid_columnconfigure(0, weight=1)
self.imageViewer.grid_columnconfigure(1, weight=0)
self.imageViewer.grid_rowconfigure(0, weight=1)
@@ -258,7 +259,7 @@ class mainWindow(Tk):
# The terminal to enter the MRZ
- self.terminal = ttk.Labelframe(self, text='Terminal de saisie de MRZ complète')
+ self.terminal = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Complete MRZ capture terminal"])
self.terminal.grid_columnconfigure(0, weight=1)
self.terminal.grid_rowconfigure(0, weight=1)
self.termframe = Frame(self.terminal)
@@ -272,7 +273,7 @@ class mainWindow(Tk):
self.termtext.grid(column=0, row=0, sticky='SW', padx=5, pady=25)
# Speed Entry Zone for 731
- self.terminal2 = ttk.Labelframe(self, text='Terminal de saisie rapide (731)')
+ self.terminal2 = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Quick entry terminal (731)"])
self.terminal2.grid_columnconfigure(0, weight=1)
self.terminal2.grid_rowconfigure(0, weight=1)
self.speed731 = Frame(self.terminal2)
@@ -294,7 +295,7 @@ class mainWindow(Tk):
self.speedResult.grid(column=2, row=0, sticky='NEW', padx=5, pady=5)
# The monitor that indicates some useful infos
- self.monitor = ttk.Labelframe(self, text='Moniteur')
+ self.monitor = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Monitor"])
self.monlog = Text((self.monitor), state='disabled', width=60, height=10, wrap='word')
self.monlog.grid(column=0, row=0, sticky='EWNS', padx=5, pady=5)
self.scrollb = ttk.Scrollbar((self.monitor), command=(self.monlog.yview))
@@ -313,17 +314,17 @@ class mainWindow(Tk):
# What is a window without a menu bar ?
menubar = Menu(self)
menu1 = Menu(menubar, tearoff=0)
- menu1.add_command(label='Nouveau', command=(self.newEntry))
- menu1.add_command(label='Ouvrir scan...', command=(self.openingScan))
+ menu1.add_command(label=lang.all[globs.CNIRlang]["New"], command=(self.newEntry))
+ menu1.add_command(label=lang.all[globs.CNIRlang]["Open scan..."], command=(self.openingScan))
menu1.add_separator()
- menu1.add_command(label='Quitter', command=(self.destroy))
- menubar.add_cascade(label='Fichier', menu=menu1)
+ menu1.add_command(label=lang.all[globs.CNIRlang]["Quit"], command=(self.destroy))
+ menubar.add_cascade(label=lang.all[globs.CNIRlang]["File"], menu=menu1)
menu3 = Menu(menubar, tearoff=0)
- menu3.add_command(label='Commandes au clavier', command=(self.helpbox))
- menu3.add_command(label='Signaler un problème', command=(self.openIssuePage))
+ menu3.add_command(label=lang.all[globs.CNIRlang]["Keyboard commands"], command=(self.helpbox))
+ menu3.add_command(label=lang.all[globs.CNIRlang]["Report a bug"], command=(self.openIssuePage))
menu3.add_separator()
- menu3.add_command(label='A propos de CNIRevelator', command=(self.infobox))
- menubar.add_cascade(label='Aide', menu=menu3)
+ menu3.add_command(label=lang.all[globs.CNIRlang]["About CNIRevelator"], command=(self.infobox))
+ menubar.add_cascade(label=lang.all[globs.CNIRlang]["Help"], menu=menu3)
self.config(menu=menubar)
# The title
@@ -347,6 +348,7 @@ class mainWindow(Tk):
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
self.update()
self.deiconify()
+ self.attributes("-topmost", 1)
self.minsize(self.winfo_width(), self.winfo_height())
# Set image
@@ -364,6 +366,9 @@ class mainWindow(Tk):
self.imageViewer.ZONE.bind("", self.rectangleSelectScan)
logfile.printdbg('Initialization successful')
+
+ if globs.CNIROpenFile:
+ self.after_idle(lambda : self.openScanFile(sys.argv[1]))
def statusUpdate(self, image=None, setplace=False):
if image:
@@ -374,12 +379,12 @@ class mainWindow(Tk):
def rectangleSelectScan(self, event):
if self.imageViewer.image:
canvas = event.widget
- print("Get coordinates : [{}, {}], for [{}, {}]".format(canvas.canvasx(event.x), canvas.canvasy(event.y), event.x, event.y))
+ #print("Get coordinates : [{}, {}], for [{}, {}]".format(canvas.canvasx(event.x), canvas.canvasy(event.y), event.x, event.y))
self.corners.append([canvas.canvasx(event.x), canvas.canvasy(event.y)])
if len(self.corners) == 2:
self.select = self.imageViewer.ZONE.create_rectangle(self.corners[0][0], self.corners[0][1], self.corners[1][0], self.corners[1][1], outline ='cyan', width = 2)
- print("Get rectangle : [{}, {}], for [{}, {}]".format(self.corners[0][0], self.corners[0][1], self.corners[1][0], self.corners[1][1]))
+ #print("Get rectangle : [{}, {}], for [{}, {}]".format(self.corners[0][0], self.corners[0][1], self.corners[1][0], self.corners[1][1]))
if len(self.corners) > 2:
self.corners = []
self.imageViewer.ZONE.delete(self.select)
@@ -434,7 +439,7 @@ class mainWindow(Tk):
invite.focus_force()
self.wait_window(invite)
- print("text : {}".format(self.validatedtext))
+ #print("text : {}".format(self.validatedtext))
self.mrzChar = ""
@@ -445,7 +450,7 @@ class mainWindow(Tk):
self.mrzChar = self.mrzChar + char
self.stringValidation("")
- print(self.mrzChar)
+ #print(self.mrzChar)
# Reinstall tesseract
except pytesseract.TesseractNotFoundError as e:
@@ -453,13 +458,13 @@ class mainWindow(Tk):
shutil.rmtree(globs.CNIRTesser)
except Exception:
pass
- showerror('Erreur de module OCR', ('Le module OCR localisé en ' + str(os.environ['PATH']) + 'est introuvable ou corrompu. Il sera réinstallé à la prochaine exécution'), parent=self)
- logfile.printerr("Tesseract error : {}. Will be reinstallated".format(e))
+ showerror(lang.all[globs.CNIRlang]["OCR module error"], (lang.all[globs.CNIRlang]["The OCR module located at {} can not be found or corrupted. It will be reinstalled at the next run"].format(os.environ['PATH'])), parent=self)
+ logfile.printerr(lang.all[globs.CNIRlang]["Tesseract error : {}. Will be reinstallated"].format(e))
# Tesseract error
except pytesseract.TesseractError as e:
logfile.printerr("Tesseract error : {}".format(e))
- showerror('Erreur de module OCR', ("Le module Tesseract a rencontré un problème : {}".format(e)), parent=self)
+ showerror(lang.all[globs.CNIRlang]["OCR module error"], (lang.all[globs.CNIRlang]["The Tesseract module encountered a problem: {}"].format(e)), parent=self)
def stringValidation(self, keysym):
@@ -478,11 +483,11 @@ class mainWindow(Tk):
self.wait_window(invite)
- self.logOnTerm("Document detecté : {}\n".format(candidates[invite.choice][2]))
+ self.logOnTerm(lang.all[globs.CNIRlang]["Document detected: {}\n"].format(candidates[invite.choice][2]))
self.mrzDecided = candidates[invite.choice]
elif len(candidates) == 1:
- self.logOnTerm("Document detecté : {}\n".format(candidates[0][2]))
+ self.logOnTerm(lang.all[globs.CNIRlang]["Document detected: {}\n"].format(candidates[0][2]))
self.mrzDecided = candidates[0]
else:
# corrects some problems
@@ -569,11 +574,11 @@ class mainWindow(Tk):
self.wait_window(invite)
- self.logOnTerm("Document re-detecté : {}\n".format(candidates[invite.choice][2]))
+ self.logOnTerm(lang.all[globs.CNIRlang]["Document detected again: {} \ n"].format(candidates[invite.choice][2]))
self.mrzDecided = candidates[invite.choice]
elif len(candidates) == 1:
- self.logOnTerm("Document re-detecté : {}\n".format(candidates[0][2]))
+ self.logOnTerm(lang.all[globs.CNIRlang]["Document detected again: {} \ n"].format(candidates[0][2]))
self.mrzDecided = candidates[0]
return "break"
@@ -583,7 +588,7 @@ class mainWindow(Tk):
regex = re.compile("[A-Z]|<|[0-9]")
# match !
if not regex.fullmatch(event.char):
- self.logOnTerm("Caractère non accepté !\n")
+ self.logOnTerm(lang.all[globs.CNIRlang]["Character not accepted !\n"])
return "break"
# Adds the entry
tempChar = self.termtext.get("1.0", "end")[:-1]
@@ -650,10 +655,22 @@ class mainWindow(Tk):
def openingScan(self):
path = ''
- path = filedialog.askopenfilename(parent=self, title='Ouvrir un scan de CNI...', filetypes=(('TIF files', '*.tif'),
+ path = filedialog.askopenfilename(parent=self, title=lang.all[globs.CNIRlang]["Open a scan of document..."], filetypes=(('TIF files', '*.tif'),
('TIF files', '*.tiff'),
('JPEG files', '*.jpg'),
('JPEG files', '*.jpeg')))
+ self.openScanFile(path)
+
+ def openScanFile(self, path):
+
+ # Check if the file is valid
+ if ( path[-3:] != 'jpg'
+ and path[-3:] != 'tif'
+ and path[-4:] != 'jpeg'
+ and path[-4:] != 'tiff' ) or not os.path.isfile(path):
+ showerror(lang.all[globs.CNIRlang]["Open a scan of document..."], lang.all[globs.CNIRlang]["The file you provided is not valid : {}"].format(path))
+ return
+
# Load an image using OpenCV
self.imageViewer.imagePath = path
self.imageViewer.imgZoom = 1
@@ -685,7 +702,7 @@ class mainWindow(Tk):
# Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage
photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(cv_img))
- self.statusUpdate(photo)
+ self.statusUpdate(photo)
def zoomInScan50(self, quantity = 50):
if self.imageViewer.image:
@@ -792,7 +809,7 @@ class mainWindow(Tk):
self.statusUpdate( photo)
except Exception as e:
logfile.printerr("Error with opencv : {}".format(e))
- traceback.print_exc(file=sys.stdout)
+ ihm.crashCNIR()
try:
# Reload an image using OpenCV
path = self.imageViewer.imagePath
@@ -810,70 +827,37 @@ class mainWindow(Tk):
self.statusUpdate(photo)
except Exception as e:
logfile.printerr("Critical error with opencv : ".format(e))
- traceback.print_exc(file=sys.stdout)
- showerror("Erreur OpenCV (traitement d'images)", "Une erreur critique s'est produite dans le gestionnaire de traitement d'images OpenCV utilisé par CNIRevelator. L'application va se réinitialiser")
+ ihm.crashCNIR()
+ showerror(lang.all[globs.CNIRlang]["OpenCV error (image processing)"], lang.all[globs.CNIRlang]["A critical error has occurred in the OpenCV image processing manager used by CNIRevelator, the application will reset itself"])
self.initialize()
def newEntry(self):
self.initialize()
- self.logOnTerm('\n\nEntrez la première ligne de MRZ svp \n')
+ self.logOnTerm('\n\n{}\n'.format(lang.all[globs.CNIRlang]["Please type a MRZ or open a scan"]))
def infobox(self):
+
Tk().withdraw()
- showinfo('A propos de CNIRevelator',
- ( 'Version du logiciel : CNIRevelator ' + globs.verstring_full + '\n\n'
- "Copyright © 2018-2019 Adrien Bourmault (neox95)" + "\n\n"
- "CNIRevelator est un logiciel libre : vous avez le droit de le modifier et/ou le distribuer "
- "dans les termes de la GNU General Public License telle que publiée par "
- "la Free Software Foundation, dans sa version 3 ou "
- "ultérieure. " + "\n\n"
- "CNIRevelator est distribué dans l'espoir d'être utile, sans toutefois "
- "impliquer une quelconque garantie de "
- "QUALITÉ MARCHANDE ou APTITUDE À UN USAGE PARTICULIER. Référez vous à la "
- "GNU General Public License pour plus de détails à ce sujet. "
- "\n\n"
- "Vous devriez avoir reçu une copie de la GNU General Public License "
- "avec CNIRevelator. Si cela n'est pas le cas, jetez un oeil à . "
- "\n\n"
- "Le module d'OCR Tesseract 4.0 est soumis à l'Apache License 2004."
- "\n\n"
- "Les bibliothèques python et l'environnement Anaconda 3 sont soumis à la licence BSD 2018-2019."
- "\n\n"
- "Le code source de ce programme est disponible sur Github à l'adresse .\n"
- "Son fonctionnement est conforme aux normes et directives du document 9303 de l'OACI régissant les documents de voyages et d'identité." + '\n\n'
- " En cas de problèmes ou demande particulière, ouvrez-y une issue ou bien envoyez un mail à neox@os-k.eu !\n\n"
+ showinfo( lang.all[globs.CNIRlang]["About CNIRevelator"],
+ (
+ lang.all[globs.CNIRlang]["ABOUT"]
),
-
parent=self)
def helpbox(self):
Tk().withdraw()
- showinfo('Aide sur les contrôles au clavier',
- ( "Terminal de saisie rapide (731) : \n\n"
- " Caractères autorisés : Alphanumériques en majuscule et le caractère '<'. Pas de minuscules ni caractères spéciaux, autrement la somme est mise à zéro \n\n"
- " Calculer résultat :\t\t\tTouche Ctrl droite \n"
- " Copier :\t\t\t\tCtrl-C \n"
- " Coller :\t\t\t\tCtrl-V \n"
- "\n\n"
- "Terminal de saisie MRZ complète : \n\n"
- " Caractères autorisés : Alphanumériques en majuscule et le caractère '<'. Pas de minuscules ni caractères spéciaux, autrement la somme est mise à zéro \n\n"
- " Calculer résultat :\t\t\tTouche Ctrl droite \n"
- " Compléter champ :\t\t\tTouche Tab \n"
- " Copier :\t\t\t\tCtrl-C \n"
- " Coller :\t\t\t\tCtrl-V \n"
- " Forcer une nouvelle détection du document :\tEchap\n"
+ showinfo( lang.all[globs.CNIRlang]["Keyboard commands"],
+ (
+ lang.all[globs.CNIRlang]["KEYBHELP"]
),
parent=self)
def openIssuePage(self):
- self.openBrowser("https://github.com/neox95/CNIRevelator/issues")
+ webbrowser.open_new("https://github.com/neox95/CNIRevelator/issues")
- def openBrowser(self, url):
- webbrowser.open_new(url)
-
def computeSigma(self):
"""
Launch the checksum computation, infos validation and display the results
@@ -890,7 +874,7 @@ class mainWindow(Tk):
self.termtext.tag_remove("nonconforme", "1.0", "end")
self.clearTerm()
- self.logOnTerm("Examen du document : {}\n\n".format(self.mrzDecided[2]))
+ self.logOnTerm(lang.all[globs.CNIRlang]["Document Review: {}\n\n"].format(self.mrzDecided[2]))
for sum in allSums:
x = sum[1] // len(self.mrzDecided[0][0]) +1
@@ -898,7 +882,7 @@ class mainWindow(Tk):
#print("index : {}.{}".format(x,y))
#print("{} == {}".format(code[sum[1]], sum[2]))
- self.logOnTerm("Somme de contrôle position {} : Lu {} VS Calculé {}\n".format(sum[1], code[sum[1]], sum[2]))
+ self.logOnTerm(lang.all[globs.CNIRlang]["Check sum position {}: Lu {} VS Calculated {} and {}\n"].format(sum[1], code[sum[1]], sum[2], sum[3]))
# if sum is facultative or if sum is ok
try:
@@ -920,7 +904,7 @@ class mainWindow(Tk):
# display the infos
for key in [ e for e in docInfos ]:
#print(docInfos[key])
- if key in ["CODE", "CTRL"]:
+ if key in ["CODE", "CTRL", "CTRLF"]:
continue
if not docInfos[key] == False:
self.infoList[key]['text'] = docInfos[key]
@@ -933,10 +917,10 @@ class mainWindow(Tk):
self.compliance = False
if self.compliance == True:
- self.STATUStxt["text"] = "CONFORME"
+ self.STATUStxt["text"] = lang.all[globs.CNIRlang]["COMPLIANT"]
self.STATUStxt["foreground"] = "green"
else:
- self.STATUStxt["text"] = "NON CONFORME"
+ self.STATUStxt["text"] = lang.all[globs.CNIRlang]["IMPROPER"]
self.STATUStxt["foreground"] = "red"
return
diff --git a/src/mrz.py b/src/mrz.py
index e51fad6..1ce646d 100644
--- a/src/mrz.py
+++ b/src/mrz.py
@@ -24,11 +24,12 @@
********************************************************************************
"""
-import re
-import logger # logger.py
import re
import datetime
+import logger # logger.py
+import lang # lang.py
+
## SEX CODES
sexcode = {'M':'Homme', 'F':'Femme', 'X':'Non spécifié'}
diff --git a/src/updater.py b/src/updater.py
index b41c16b..0840c78 100644
--- a/src/updater.py
+++ b/src/updater.py
@@ -24,7 +24,6 @@
"""
from win32com.client import Dispatch
-import traceback
import sys
import time
import os
@@ -38,6 +37,7 @@ import ihm # ihm.py
import logger # logger.py
import globs # globs.py
import downloader # downloader.py
+import lang # lang.py
UPDATE_IS_MADE = False
UPATH = ' '
@@ -81,47 +81,6 @@ def exitProcess(arg):
process.terminate()
sys.exit(arg)
-def runPowershell(scriptblock, cwd=os.getcwd()):
- """
- Executes a powershell command
- """
- log.debug("Running PowerShell Block:\r\n%s", scriptblock)
- log.debug("Current Directory: %s\r\n" % cwd)
- psProc = subprocess.Popen([r'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe',
- '-ExecutionPolicy', 'Bypass',
- '-noprofile',
- '-c', '-',],
- cwd=cwd,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- stdoutdata, stderrdata = psProc.communicate(scriptblock)
-
- if stdoutdata:
- log.debug("Script Output:\r\n%s" % stdoutdata)
- elif not stderrdata:
- log.debug("Script completed succssfully (no stdout/stderr).")
- if stderrdata:
- log.error("Script Error:\r\n%s" % stderrdata)
-
- return stdoutdata, stderrdata
-
-
-def getCertificates(server_list, location="LocalMachine", store="My"):
- """
- Returns the json data of all installed certificates
- """
- cmd = '''
-$sb = { ls Cert:\%s\%s | Select Subject,ThumbPrint }
-$Servers = '%s' | ConvertFrom-Json
-
-Invoke-Command -ComputerName $Servers -ScriptBlock $sb -Authentication Negotiate | ConvertTo-Json -Depth 999
- ''' % (location, store, json.dumps(server_list))
- stdoutdata, stderrdata = runPowershell(cmd)
- return json.loads(stdoutdata)
-
-
-
def getLatestVersion(credentials):
"""
Returns the latest version of the software
@@ -228,7 +187,7 @@ def tessInstall(PATH, credentials):
# Unzip Tesseract
logfile.printdbg("Unzipping the package")
- launcherWindow.printmsg('Installing the updates')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]["Installing the updates"])
zip_ref = zipfile.ZipFile(PATH + '\\downloads\\TsrtPackage.zip', 'r')
zip_ref.extractall(PATH)
zip_ref.close()
@@ -261,7 +220,7 @@ def batch(credentials):
getTheUpdate = downloader.newdownload(credentials, finalurl, globs.CNIRFolder + '\\downloads\\CNIPackage.zip', "CNIRevelator {}.{}.{}".format(finalver[0], finalver[1], finalver[2])).download()
- launcherWindow.printmsg('Verifying download...')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]["Verifying download..."])
# CHECKSUM
BUF_SIZE = 65536 # lets read stuff in 64kb chunks!
@@ -286,7 +245,7 @@ def batch(credentials):
global UPATH
UPATH = globs.CNIRFolder + '\\..\\CNIRevelator' + "{}.{}.{}".format(finalver[0], finalver[1], finalver[2])
logfile.printdbg("Make place")
- launcherWindow.printmsg('Preparing installation...')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]["Preparing installation..."])
# Cleanup
try:
shutil.rmtree(UPATH + 'temp')
@@ -298,7 +257,7 @@ def batch(credentials):
logfile.printdbg('Unable to cleanup : ' +str(e))
# Unzip
logfile.printdbg("Unzipping the package")
- launcherWindow.printmsg('Installing the updates')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]["Installing the updates"])
zip_ref = zipfile.ZipFile(globs.CNIRFolder + '\\downloads\\CNIPackage.zip', 'r')
zip_ref.extractall(UPATH + "temp")
zip_ref.close()
@@ -309,9 +268,15 @@ def batch(credentials):
logfile.printdbg('Extracted :' + UPATH + '\\CNIRevelator.exe')
# Make a shortcut
- createShortcut("CNIRevelator.lnk", UPATH + '\\CNIRevelator.exe', UPATH)
+ # hide main window
+ root = Tk()
+ root.withdraw()
+ res = askquestion(lang.all[globs.CNIRlang]["Shortcut creation"], lang.all[globs.CNIRlang]["Would you like to create/update the shortcut for CNIRevelator on your desktop ?"])
+ if res == "yes":
+ createShortcut("CNIRevelator.lnk", UPATH + '\\CNIRevelator.exe', UPATH)
+ root.destroy()
- launcherWindow.printmsg('Success !')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]["Success !"])
# Cleanup
try:
@@ -319,7 +284,7 @@ def batch(credentials):
except:
pass
# Time to quit
- launcherWindow.printmsg('Launched the new process.')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]["Launching the new version..."])
global UPDATE_IS_MADE
UPDATE_IS_MADE = True
return True
@@ -335,19 +300,19 @@ def umain():
if not credentials.valid:
logfile.printerr("Credentials Error. No effective update !")
- launcherWindow.printmsg('Credentials Error. No effective update !')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]["Credentials Error. No effective update !"])
time.sleep(2)
launcherWindow.exit()
return 0
# Cleaner for the old version if detected
- if len(sys.argv) > 2:
+ if len(sys.argv) > 2 and str(sys.argv[1]) == "DELETE":
globs.CNIRNewVersion = True
- launcherWindow.printmsg('Deleting old version !')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]["Deleting old version"])
logfile.printdbg("Old install detected : {}".format(sys.argv[1]))
while os.path.exists(str(sys.argv[2])):
try:
- os.remove(str(sys.argv[2]))
+ shutil.rmtree(str(sys.argv[2]))
except Exception as e:
logfile.printerr(str(e))
logfile.printdbg('Trying stop the process !')
@@ -361,45 +326,23 @@ def umain():
else:
logfile.printdbg('Terminating process !')
process.terminate()
- os.remove(str(sys.argv[2]))
+ shutil.rmtree(str(sys.argv[2]))
break
except Exception as e:
logfile.printerr(str(e))
launcherWindow.printmsg('Fail :{}'.format(e))
- launcherWindow.printmsg('Starting...')
- elif len(sys.argv) > 1:
- globs.CNIRNewVersion = True
- launcherWindow.printmsg('Deleting old version !')
- logfile.printdbg("Old install detected : {}".format(sys.argv[1]))
- while os.path.exists(str(sys.argv[1])):
- try:
- shutil.rmtree(str(sys.argv[1]))
- except Exception as e:
- logfile.printerr(str(e))
- logfile.printdbg('Trying stop the process !')
- launcherWindow.printmsg('Fail :{}'.format(e))
- try:
- for process in psutil.process_iter():
- if process.name() == 'CNIRevelator.exe':
- logfile.printdbg('Process found. Command line: {}'.format(process.cmdline()))
- if process.pid == os.getpid():
- logfile.printdbg("Don't touch us ! {} = {}".format(process.pid, os.getpid()))
- else:
- logfile.printdbg('Terminating process !')
- process.terminate()
- shutil.rmtree(str(sys.argv[1]))
- break
- except Exception as e:
- logfile.printerr(str(e))
- launcherWindow.printmsg('Fail :{}'.format(e))
- launcherWindow.printmsg('Starting...')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]['Starting...'])
+
+ # check we want open a file
+ elif len(sys.argv) > 1 and str(sys.argv[1]) != "DELETE":
+ globs.CNIROpenFile = True
try:
try:
# EXECUTING THE UPDATE BATCH
success = batch(credentials)
except Exception as e:
- logfile.printerr("An error occured on the thread : " + str(traceback.format_exc()))
+ ihm.crashCNIR()
launcherWindow.printmsg('ERROR : ' + str(e))
time.sleep(3)
launcherWindow.exit()
@@ -410,7 +353,7 @@ def umain():
launcherWindow.printmsg('Software is up-to-date !')
else:
logfile.printerr("An error occured. No effective update !")
- launcherWindow.printmsg('An error occured. No effective update !')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]['An error occured. No effective update !'])
time.sleep(2)
launcherWindow.exit()
return 0
@@ -419,7 +362,7 @@ def umain():
launcherWindow.exit()
return 0
except:
- logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
+ ihm.crashCNIR()
launcherWindow.exit()
sys.exit(2)
return 2
@@ -429,7 +372,7 @@ def umain():
# INSTALLING TESSERACT OCR
success = tessInstall(globs.CNIRFolder, credentials)
except Exception as e:
- logfile.printerr("An error occured on the thread : " + str(traceback.format_exc()))
+ ihm.crashCNIR()
launcherWindow.printmsg('ERROR : ' + str(e))
time.sleep(3)
launcherWindow.exit()
@@ -437,16 +380,16 @@ def umain():
if success:
logfile.printdbg("Software is up-to-date !")
- launcherWindow.printmsg('Software is up-to-date !')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]['Software is up-to-date !'])
else:
logfile.printerr("An error occured. No effective update !")
- launcherWindow.printmsg('An error occured. No effective update !')
+ launcherWindow.printmsg(lang.all[globs.CNIRlang]['An error occured. No effective update !'])
time.sleep(2)
launcherWindow.exit()
return 0
except:
- logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
+ ihm.crashCNIR()
launcherWindow.exit()
sys.exit(2)
return 2