diff --git a/VERSIONS.LST b/VERSIONS.LST index 3e6f316..e784c3f 100644 --- a/VERSIONS.LST +++ b/VERSIONS.LST @@ -1,2 +1,2 @@ -# ver|url|checksum, and | as separator, one version per || - +# ver|url|checksum, and | as separator, one version per || +3.1.2|https://github.com/neox95/CNIRevelator/releases/download/3.1.1/CNIRevelator.zip|cb2f4999e7265297008074e0e2beacbb2943a004|| \ No newline at end of file diff --git a/src/CNIRevelator.py b/src/CNIRevelator.py index 3fe7fb0..308d41c 100644 --- a/src/CNIRevelator.py +++ b/src/CNIRevelator.py @@ -23,22 +23,26 @@ * along with CNIRevelator. If not, see . * ******************************************************************************** """ - -import sys +# Import critical files import os -import subprocess import threading -import traceback -import psutil -import launcher # launcher.py" -import updater # updater.py -import globs # globs.py -import pytesseract # pytesseract.py +import lang # lang.py import logger # logger.py +import globs # globs.py +import critical # critical.py +# Import all other files and crash if necessary +try: -from main import * # main.py + import launcher # launcher.py" + import updater # updater.py + import pytesseract # pytesseract.py + import ihm # ihm.py + from tkinter.messagebox import * + from tkinter import * +except: + critical.crashCNIR() # Global handler logfile = logger.logCur @@ -59,15 +63,17 @@ 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"])) + # changelog if globs.CNIRNewVersion: - showinfo('Changelog : résumé de mise à jour', ('Version du logiciel : CNIRevelator ' + globs.verstring_full + '\n\n' + globs.changelog), parent=mainw) + mainw.after_idle(mainw.showChangeLog) + 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 ! ***') @@ -75,30 +81,45 @@ def main(): ## BOOTSTRAP OF CNIREVELATOR - try: - launcherThread = threading.Thread(target=updater.umain, daemon=False) - launcher.lmain(launcherThread) -except Exception: - updater.exitProcess(1) -if updater.UPDATE_IS_MADE: - # Launch app ! - args = updater.UPATH + '\\CNIRevelator.exe ' + globs.CNIRFolder - cd = updater.UPATH - for i in range(0,3): - try: - updater.spawnProcess(args, cd) - except: - time.sleep(3) - continue - break - updater.exitProcess(0) + try: + # LANGUAGE + lang.readLang() + except: + critical.crashCNIR() + updater.exitProcess(1) -# Here we go ! -try: - main() -except Exception as e: - traceback.print_exc(file=sys.stdout) + from main import * # main.py + # GO + try: + launcherThread = threading.Thread(target=updater.umain, daemon=False) + launcher.lmain(launcherThread) + except Exception: + critical.crashCNIR() + updater.exitProcess(1) + + if updater.UPDATE_IS_MADE: + # Launch app ! + args = updater.UPATH + '\\CNIRevelator.exe' + " DELETE " + globs.CNIRFolder + cd = updater.UPATH + for i in range(0,3): + try: + updater.spawnProcess(args, cd) + except: + time.sleep(3) + continue + break + updater.exitProcess(0) + + # Here we go ! + try: + main() + except Exception as e: + critical.crashCNIR() + updater.exitProcess(1) + +except: + critical.crashCNIR() updater.exitProcess(0) \ No newline at end of file diff --git a/src/critical.py b/src/critical.py new file mode 100644 index 0000000..e44639e --- /dev/null +++ b/src/critical.py @@ -0,0 +1,66 @@ +""" +******************************************************************************** +* CNIRevelator * +* * +* Desc: Critical Stuff for CNIRevelator * +* * +* 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 . * +******************************************************************************** +""" +from tkinter.messagebox import * +from importlib import reload +from tkinter import * +import webbrowser +import traceback +import psutil +import os + +import lang # lang.py +import logger # logger.py +import globs # globs.py + +def crashCNIR(shutdown=True): + """ + very last solution + """ + + try: + root = Tk() + root.withdraw() + logfile = logger.logCur + 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"], parent=root) + res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to open the log file ?"], parent=root) + if res == "yes": + webbrowser.open_new(globs.CNIRErrLog) + 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 ?"], parent=root) + if res == "yes": + webbrowser.open_new("https://github.com/neox95/CNIRevelator/issues") + root.destroy() + + # Quit ? + if not shutdown: + return + + # Quit totally without remain in memory + for process in psutil.process_iter(): + if process.pid == os.getpid(): + process.terminate() + sys.exit(arg) + except: + traceback.print_exc() \ No newline at end of file diff --git a/src/downloader.py b/src/downloader.py index c10a7e2..3faa243 100644 --- a/src/downloader.py +++ b/src/downloader.py @@ -32,9 +32,11 @@ from Crypto.Cipher import AES from requests import Session from time import time +import critical # critical.py import logger # logger.py import globs # globs.py import ihm # ihm.py +import lang # lang.py class AESCipher(object): @@ -184,8 +186,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 +203,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..f3b0852 100644 --- a/src/globs.py +++ b/src/globs.py @@ -26,12 +26,9 @@ import os # CNIRevelator version verType = "final release" -version = [3, 1, 0] +version = [3, 1, 1] verstring_full = "{}.{}.{} {}".format(version[0], version[1], version[2], verType) 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" CNIRTesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8' CNIRFolder = os.getcwd() @@ -47,3 +44,28 @@ CNIRMainLog = CNIRFolder + '\\logs\\main.log' CNIRUrlConfig = CNIRFolder + '\\config\\urlconf.ig' CNIRVerStock = CNIRFolder + '\\downloads\\versions.lst' CNIREnv = CNIRFolder + '\\Data\\' + + +CNIRTesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8' +CNIRFolder = os.path.dirname(os.path.realpath(__file__)) +CNIRLColor = "#006699" +CNIRName = "CNIRevelator {}".format(verstring) +CNIRCryptoKey = '82Xh!efX3#@P~2eG' + +CNIRLangFile = CNIRFolder + '\\config\\lang.ig' +CNIRlang = "fr" + +CNIRConfig = CNIRFolder + '\\config\\conf.ig' +CNIRTesser = CNIRFolder + '\\Tesseract-OCR4\\' +CNIRErrLog = CNIRFolder + '\\logs\\error.log' +CNIRMainLog = CNIRFolder + '\\logs\\main.log' +CNIRUrlConfig = CNIRFolder + '\\config\\urlconf.ig' +CNIRVerStock = CNIRFolder + '\\downloads\\versions.lst' +CNIREnv = CNIRFolder + '\\Data\\' + +CNIRBetaURL = "https://raw.githubusercontent.com/neox95/CNIRevelator/v3.1/VERSIONS.LST" +CNIRDefaultURL = "https://raw.githubusercontent.com/neox95/CNIRevelator/master/VERSIONS.LST" + +CNIRNewVersion = False +CNIROpenFile = False +debug = True \ No newline at end of file diff --git a/src/ihm.py b/src/ihm.py index 1c7d153..d6fb8ca 100644 --- a/src/ihm.py +++ b/src/ihm.py @@ -1,4 +1,4 @@ -""" +""" ******************************************************************************** * CNIRevelator * * * @@ -23,19 +23,22 @@ ******************************************************************************** """ -from tkinter import * -import webbrowser from tkinter.messagebox import * +from tkinter import * from tkinter import filedialog from tkinter import ttk -import cv2 import PIL.Image, PIL.ImageTk import traceback +import webbrowser +import cv2 +import critical # critical.py import logger # logger.py import globs # globs.py import lang # lang.py +import updater # updater.py +import critical # critical.py controlKeys = ["Escape", "Right", "Left", "Up", "Down", "Home", "End", "BackSpace", "Delete", "Inser", "Shift_L", "Shift_R", "Control_R", "Control_L"] @@ -117,21 +120,22 @@ class LoginDialog(Toplevel): self.login = '' super().__init__(parent) self.title(lang.all[globs.CNIRlang]["Connection"]) - Label(self, text='IPN : ').pack() - self.entry_login = Entry(self) + self["background"] = "white" + Label(self, text='IPN : ', bg="white").pack(fill=Y) + self.entry_login = ttk.Entry(self) self.entry_login.insert(0, '') self.entry_login.pack() - Label(self, text='{} : '.format(lang.all[globs.CNIRlang]["Password"])).pack() - self.entry_pass = Entry(self, show='*') + Label(self, text='{} : '.format(lang.all[globs.CNIRlang]["Password"]), bg="white").pack(fill=Y) + self.entry_pass = ttk.Entry(self, show='*') self.entry_pass.insert(0, '') - self.entry_pass.pack() - Button(self, text=lang.all[globs.CNIRlang]["Connection"], command=(self.connecti)).pack() + self.entry_pass.pack(fill=Y) + ttk.Button(self, text=lang.all[globs.CNIRlang]["Connection"], command=(self.connecti)).pack(fill=Y, pady=10) + self.update() self.resizable(width=False, height=False) ws = self.winfo_screenwidth() hs = self.winfo_screenheight() - w = hs / 10 - h = ws / 18 - self.update() + w = self.winfo_reqwidth() + 5 + h = self.winfo_reqheight() if getattr(sys, 'frozen', False): self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico') else: @@ -146,6 +150,124 @@ class LoginDialog(Toplevel): self.key = self.entry_pass.get().strip() self.destroy() +class ChangelogDialog(Toplevel): + + def __init__(self, parent, text): + super().__init__(parent) + + self.title(lang.all[globs.CNIRlang]["Show Changelog"]) + self["background"] = "white" + + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + self.text = Text(self, wrap='word', width=55, height=15, borderwidth=0, font="TkDefaultFont", bg="white") + self.text.grid(column=0, row=0, sticky='EWNS', padx=5, pady=5) + + ttk.Button(self, text="OK", command=(self.oki)).grid(column=0, row=1, pady=5) + + self.scrollb = ttk.Scrollbar(self, command=(self.text.yview)) + self.scrollb.grid(column=1, row=0, sticky='EWNS', padx=5, pady=5) + self.text['yscrollcommand'] = self.scrollb.set + + self.text.insert('end', text) + self.text['state'] = 'disabled' + + self.update() + self.resizable(width=False, height=False) + ws = self.winfo_screenwidth() + hs = self.winfo_screenheight() + w = self.winfo_reqwidth() + 5 + h = self.winfo_reqheight() + if getattr(sys, 'frozen', False): + self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico') + else: + self.iconbitmap('id-card.ico') + x = ws / 2 - w / 2 + y = hs / 2 - h / 2 + self.geometry('%dx%d+%d+%d' % (w, h, x, y)) + self.bind("", self.oki) + + def oki(self, event=None): + self.destroy() + +class langDialog(Toplevel): + + def __init__(self, parent): + super().__init__(parent) + + self.title(lang.all[globs.CNIRlang]["Language"]) + + Label(self, text=lang.all[globs.CNIRlang]["Please choose your language : "]).pack(fill=Y) + + vals = [i for i in lang.all] + for i in range(len(lang.all)): + ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]).pack(fill=Y) + + ttk.Button(self, text="OK", command=(self.oki)).pack(fill=Y, pady=5) + + self.update() + self.resizable(width=False, height=False) + ws = self.winfo_screenwidth() + hs = self.winfo_screenheight() + w = self.winfo_reqwidth() + 5 + h = self.winfo_reqheight() + if getattr(sys, 'frozen', False): + self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico') + else: + self.iconbitmap('id-card.ico') + x = ws / 2 - w / 2 + y = hs / 2 - h / 2 + self.geometry('%dx%d+%d+%d' % (w, h, x, y)) + self.bind("", self.oki) + + def oki(self, event=None): + self.destroy() + + def createRegister(self, i): + def register(): + lang.updateLang([j for j in lang.all][i]) + return register + +class updateSetDialog(Toplevel): + + def __init__(self, parent): + super().__init__(parent) + + self.title(lang.all[globs.CNIRlang]["Update options"]) + + Label(self, text=lang.all[globs.CNIRlang]["Please choose your update channel : "]).pack(fill=Y) + + self.vals = ["Stable", "Beta"] + vals = self.vals + for i in range(len(vals)): + ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]).pack(fill=Y) + + ttk.Button(self, text="OK", command=(self.oki)).pack(fill=Y, pady=5) + + self.update() + self.resizable(width=False, height=False) + ws = self.winfo_screenwidth() + hs = self.winfo_screenheight() + w = self.winfo_reqwidth() + 5 + h = self.winfo_reqheight() + if getattr(sys, 'frozen', False): + self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico') + else: + self.iconbitmap('id-card.ico') + x = ws / 2 - w / 2 + y = hs / 2 - h / 2 + self.geometry('%dx%d+%d+%d' % (w, h, x, y)) + self.bind("", self.oki) + + def oki(self, event=None): + self.destroy() + + def createRegister(self, i): + def register(): + updater.updateChannel(self.vals[i]) + return register + class LauncherWindow(Tk): def __init__(self): @@ -153,6 +275,12 @@ class LauncherWindow(Tk): Tk.__init__(self) self.resizable(width=False, height=False) + # icon + if getattr(sys, 'frozen', False): + self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico') + else: + self.iconbitmap('id-card.ico') + # Setting up the geometry ws = self.winfo_screenwidth() hs = self.winfo_screenheight() @@ -201,11 +329,6 @@ class LauncherWindow(Tk): self.update() self.progressBar.grid(row=1, sticky='S') - - if getattr(sys, 'frozen', False): - self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico') - else: - self.iconbitmap('id-card.ico') logfile = logger.logCur logfile.printdbg('Launcher IHM successful') self.protocol('WM_DELETE_WINDOW', lambda : 0) @@ -233,22 +356,20 @@ class ResizeableCanvas(Canvas): # 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() +class StatusBar(Frame): + def __init__(self, master): + Frame.__init__(self, master) + self.label = Label(self, bd=1, relief=SUNKEN, anchor=W) + self.label.pack(fill=X) + + def set(self, text): + self.label.config(text="Document : " + text.lower()) + self.label.update_idletasks() + + def clear(self): + self.label.config(text="") + self.label.update_idletasks() ## Global Handler launcherWindowCur = LauncherWindow() diff --git a/src/lang.py b/src/lang.py new file mode 100644 index 0000000..7c2c166 --- /dev/null +++ b/src/lang.py @@ -0,0 +1,1465 @@ +""" +******************************************************************************** +* 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 os + +import globs # globs.py +import critical # critical.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 the " +"log file ?" : "Souhaitez-vous ouvrir le fichier de log ?", +"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" : "N° 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", +"Settings" : "Paramètres", +"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", + +"CHANGELOG" : "Version 3.1.1 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug sévère du système de mise à jour\n\n" + \ +"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\n- Ajout des canaux de mise-à-jour\n\n" + \ +"Version 3.0.8 finale\nCorrectif : bug du système de mise-à-jour'\n\n" + \ +"Version 3.0.6 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement de l'apparence du launcher de l'application\n- Améliorations de l'interface, notamment de la stabilité\n- Ajout de la signature numérique de l'exécutable\n\n" + \ +"Version 3.0.7 finale\nMise-à-jour majeure avec les corrections suivantes :\n- Refonte de l'interface utilisateur\n- Fonction OCR intégrée à l'application avec support des TIFF et JPEG\n- Corrections d'erreurs sur le traitement des VISA de type A et B, ainsi que les titres de séjour\n\n" + \ +"Version 3.0.6 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement de l'apparence du launcher de l'application\n- Améliorations de l'interface, notamment de la stabilité\n- Ajout de la signature numérique de l'exécutable\n\n" + \ +"Version 3.0.5 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement de l'icône de l'exécutable afin de refléter le changement de version majeur accompli en 3.0\n\n" + \ +"Version 3.0.4 \nMise-à-jour mineure avec les corrections suivantes :\n- Correction d'un bug affectant le système de mise-à-jour\n\n" + \ +"Version 3.0.3 \nMise-à-jour mineure avec les corrections suivantes :\n- Correction d'un bug affectant le changelog\n- Correction d'une erreur avec la touche Suppr Arrière et Suppr causant une perte de données\n\n" + \ +"Version 3.0.2 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement d'icône de l'exécutable\n- Correction d'un bug affectant le logging\n- Correction d'un bug affectant la détection de documents\n- Et autres modifications mineures\n\n" + \ +"Version 3.0.1 \nMise-à-jour majeure avec les corrections suivantes :\n- Renouvellement de la signature numérique de l'exécutable\n- Amélioration de présentation du log en cas d'erreur\n- Refonte totale du code source et désobfuscation\n- Téléchargements en HTTPS fiables avec somme de contrôle\n- Nouveaux terminaux d'entrées : un rapide (731) et un complet\n- Détection des documents améliorée, possibilité de choix plus fin\nEt les regressions suivantes :\n- Suppression temporaire de la fonction de lecture OCR. Retour planifié pour une prochaine version", + +"Document Review: {}\n\n" : "Examen du document : {}\n\n", +"Calculated {} [facultative]\n" : "Checksum position {}: Lu {} VS Calculé {} [facultatif]\n", +"Checksum position {}: Lu {} VS " +"Calculated {}\n" : "Checksum position {}: Lu {} VS Calculé {}\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é : {}", +"Update options" : "Options de mise-à-jour", +"Language" : "Langue", +"Show Changelog" : "Résumé de mise-à-jour", +"Please choose your language : " : "Merci de choisir votre langue : ", +"Please choose your update " +"channel : " : "Merci de choisir votre canal de mise-à-jour : ", +"Passeport" : "Passeport", +"Carte-passeport" : "Carte-passeport", +"Titre d'identité/de voyage" : "Titre d'identité/de voyage", +"Certificat de membre d'équipage" : "Certificat de membre d'équipage", +"Visa de type A" : "Visa de type A", +"Visa de type B" : "Visa de type B", +"Carte de séjour" : "Carte de séjour", +"Pièce d'identité/de voyage" : "Pièce d'identité/de voyage", +"Pièce d'identité FR" : "Pièce d'identité FR", +"Permis de conduire" : "Permis de conduire", + +"LANDCODE2" : { + 'AW': 'Aruba', + 'AF': 'Afghanistan', + 'AO': 'Angola', + 'AI': 'Anguilla', + 'AL': 'Albanie', + 'AD': 'Andorre', + 'AE': 'Emirats arabes unis', + 'AR': 'Argentine', + 'AM': 'Arménie', + 'AS': 'Samoa américaines', + 'AQ': 'Antarctique', + 'TF': 'Terres australes et antarctiques françaises', + 'AG': 'Antigua-et-Barbuda', + 'AU': 'Australie', + 'AT': 'Autriche', + 'AZ': 'Azerbaidjan', + 'BI': 'Burundi', + 'BE': 'Belgique', + 'BJ': 'Benin', + 'BQ': 'Pays-Bas caribéens', + 'BF': 'Burkina Faso', + 'BD': 'Bangladesh', + 'BG': 'Bulgarie', + 'BH': 'Bahrein', + 'BS': 'Bahamas', + 'BA': 'Bosnie-Herzegovine', + 'BL': 'Saint-Barthélemy', + 'BY': 'Bielorussie', + 'BZ': 'Belize', + 'BM': 'Bermudes', + 'BO': 'Bolivie', + 'BR': 'Brésil', + 'BB': 'Barbade', + 'BN': 'Brunei', + 'BT': 'Bhoutan', + 'BW': 'Botswana', + 'CF': 'République Centrafricaine', + 'CA': 'Canada', + 'CC': 'Îles Cocos', + 'CH': 'Suisse', + 'CL': 'Chili', + 'CN': 'Chine', + 'CI': "Côte d'Ivoire", + 'CM': 'Cameroun', + 'CD': 'Congo (République démocratique)', + 'CG': 'Congo (République)', + 'CK': 'Îles Cook', + 'CO': 'Colombie', + 'KM': 'Comores', + 'CV': 'Cap-Vert', + 'CR': 'Costa Rica', + 'CU': 'Cuba', + 'CW': 'Curaçao', + 'CX': 'Île Christmas', + 'KY': 'Caimans', + 'CY': 'Chypre', + 'CZ': 'Tchéquie', + 'DE': 'Allemagne', + 'DJ': 'Djibouti', + 'DM': 'Dominique', + 'DK': 'Danemark', + 'DO': 'République dominicaine', + 'DZ': 'Algérie', + 'EC': 'Equateur', + 'EG': 'Egypte', + 'ER': 'Erythrée', + 'EH': 'Sahara occidental', + 'ES': 'Espagne', + 'EE': 'Estonie', + 'ET': 'Ethiopie', + 'FI': 'Finlande', + 'FJ': 'Fidji', + 'FK': 'Îles Malouines', + 'FR': 'France', + 'FO': 'Féroé', + 'FM': 'Micronésie', + 'GA': 'Gabon', + 'GB': 'Royaume-Uni', + 'GE': 'Géorgie', + 'GG': 'Guernesey', + 'GH': 'Ghana', + 'GI': 'Gibraltar', + 'GN': 'Guinée', + 'GP': 'Guadeloupe', + 'GM': 'Gambie', + 'GW': 'Guinée-Bissau', + 'GQ': 'Guinée équatoriale', + 'GR': 'Grèce', + 'GD': 'Grenade', + 'GL': 'Groenland', + 'GT': 'Guatemala', + 'GF': 'Guyane', + 'GU': 'Guam', + 'GY': 'Guyana', + 'HK': 'Hong Kong', + 'HN': 'Honduras', + 'HR': 'Croatie', + 'HT': 'Haïti', + 'HU': 'Hongrie', + 'ID': 'Indonésie', + 'IM': 'Île de Man', + 'IN': 'Inde', + 'IO': "Territoire britannique de l'océan Indien", + 'IE': 'Irlande', + 'IR': 'Irak', + 'IQ': 'Iran', + 'IS': 'Islande', + 'IL': 'Israël', + 'IT': 'Italie', + 'JM': 'Jamaïque', + 'JE': 'Jersey', + 'JO': 'Jordanie', + 'JP': 'Japon', + 'KZ': 'Kazakhstan', + 'KE': 'Kenya', + 'KG': 'Kirghizistan', + 'KH': 'Cambodge', + 'KI': 'Kiribati', + 'KN': 'Saint-Christophe-et-Niévès', + 'KR': 'Corée du Sud', + 'KW': 'Koweït', + 'LA': 'Laos', + 'LB': 'Liban', + 'LR': 'Liberia', + 'LY': 'Libye', + 'LC': 'Sainte-Lucie', + 'LI': 'Liechtenstein', + 'LK': 'Sri Lanka', + 'LS': 'Lesotho', + 'LT': 'Lituanie', + 'LU': 'Luxembourg', + 'LV': 'Lettonie', + 'MO': 'Macao', + 'MF': 'Sint-Maarten', + 'MA': 'Maroc', + 'MC': 'Monaco', + 'MD': 'Moldavie', + 'MG': 'Madagascar', + 'MV': 'Maldives', + 'MX': 'Mexique', + 'MH': 'Marshall', + 'MK': 'Macedoine', + 'ML': 'Mali', + 'MT': 'Malte', + 'MM': 'Birmanie', + 'ME': 'Monténégro', + 'MN': 'Mongolie', + 'MP': 'Îles Mariannes du Nord', + 'MZ': 'Mozambique', + 'MR': 'Mauritanie', + 'MS': 'Montserrat', + 'MQ': 'Martinique', + 'MU': 'Maurice', + 'MW': 'Malawi', + 'MY': 'Malaisie', + 'YT': 'Mayotte', + 'NA': 'Namibie', + 'NC': 'Nouvelle-Calédonie', + 'NE': 'Niger', + 'NF': 'Île Norfolk', + 'NG': 'Nigeria', + 'NI': 'Nicaragua', + 'NU': 'Niue', + 'NL': 'Pays-Bas', + 'NO': 'Norvège', + 'NP': 'Nepal', + 'NR': 'Nauru', + 'NZ': 'Nouvelle-Zélande', + 'OM': 'Oman', + 'PK': 'Pakistan', + 'PA': 'Panama', + 'PN': 'Îles Pitcairn', + 'PE': 'Pérou', + 'PH': 'Philippines', + 'PW': 'Palaos', + 'PG': 'Papouasie-Nouvelle-Guinée', + 'PL': 'Pologne', + 'PR': 'Porto Rico', + 'KP': 'Corée du Nord', + 'PT': 'Portugal', + 'PY': 'Paraguay', + 'PS': 'Palestine', + 'PF': 'Polynésie française', + 'QA': 'Qatar', + 'RE': 'Réunion', + 'RO': 'Roumanie', + 'RU': 'Russie', + 'RW': 'Rwanda', + 'SA': 'Arabie saoudite', + 'SD': 'Soudan', + 'SN': 'Sénégal', + 'SG': 'Singapour', + 'GS': 'Georgie du Sud-et-les iles Sandwich du Sud', + 'SH': 'Sainte-Hélène, Ascension et Tristan da Cunha', + 'SJ': 'Svalbard et île Jan Mayen', + 'SB': 'Salomon', + 'SL': 'Sierra Leone', + 'SV': 'Salvador', + 'SM': 'Saint-Marin', + 'SO': 'Somalie', + 'PM': 'Saint-Pierre-et-Miquelon', + 'RS': 'Serbie', + 'SS': 'Soudan du Sud', + 'ST': 'Sao Tomé-et-Principe', + 'SR': 'Suriname', + 'SK': 'Slovaquie', + 'SI': 'Slovénie', + 'SE': 'Suède', + 'SZ': 'eSwatani', + 'SX': 'Saint-Martin ', + 'SC': 'Seychelles', + 'SY': 'Syrie', + 'TC': 'Îles Turques-et-Caïques', + 'TD': 'Tchad', + 'TG': 'Togo', + 'TH': 'Thaïlande', + 'TJ': 'Tadjikistan', + 'TK': 'Tokelau', + 'TM': 'Turkmenistan', + 'TL': 'Timor oriental', + 'TO': 'Tonga', + 'TT': 'Trinité-et-Tobago', + 'TN': 'Tunisie', + 'TR': 'Turquie', + 'TV': 'Tuvalu', + 'TW': 'Taiwan', + 'TZ': 'Tanzanie', + 'UG': 'Ouganda', + 'UA': 'Ukraine', + 'UY': 'Uruguay', + 'US': 'Etats-Unis', + 'UZ': 'Ouzbékistan', + 'VA': 'Saint-Siège (État de la Cité du Vatican)', + 'VC': 'Saint-Vincent-et-les-Grenadines', + 'VE': 'Venezuela', + 'VG': 'Îles Vierges britanniques', + 'VI': 'Îles Vierges des États-Unis', + 'VN': 'Viêt Nam', + 'VU': 'Vanuatu', + 'WF': 'Wallis-et-Futuna', + 'WS': 'Samoa', + 'XK': 'Kosovo', + 'YE': 'Yémen', + 'ZA': 'Afrique du Sud', + 'ZM': 'Zambie', + 'ZW': 'Zimbabwe' + }, + +"LANDCODE3" : { + 'ABW': 'Aruba', + 'AFG': 'Afghanistan', + 'AGO': 'Angola', + 'AIA': 'Anguilla', + 'ALB': 'Albanie', + 'AND': 'Andorre', + 'ARE': 'Emirats arabes unis', + 'ARG': 'Argentine', + 'ARM': 'Arménie', + 'ASM': 'Samoa américaines', + 'ATA': 'Antarctique', + 'ATF': 'Terres australes et antarctiques françaises', + 'ATG': 'Antigua-et-Barbuda', + 'AUS': 'Australie', + 'AUT': 'Autriche', + 'AZE': 'Azerbaidjan', + 'BDI': 'Burundi', + 'BEL': 'Belgique', + 'BEN': 'Benin', + 'BES': 'Pays-Bas caribéens', + 'BFA': 'Burkina Faso', + 'BGD': 'Bangladesh', + 'BGR': 'Bulgarie', + 'BHR': 'Bahrein', + 'BHS': 'Bahamas', + 'BIH': 'Bosnie-Herzegovine', + 'BLM': 'Saint-Barthélemy', + 'BLR': 'Bielorussie', + 'BLZ': 'Belize', + 'BMU': 'Bermudes', + 'BOL': 'Bolivie', + 'BRA': 'Brésil', + 'BRB': 'Barbade', + 'BRN': 'Brunei', + 'BTN': 'Bhoutan', + 'BWA': 'Botswana', + 'CAF': 'République Centrafricaine', + 'CAN': 'Canada', + 'CCK': 'Îles Cocos', + 'CHE': 'Suisse', + 'CHL': 'Chili', + 'CHN': 'Chine', + 'CIV': "Côte d'Ivoire", + 'CMR': 'Cameroun', + 'COD': 'Congo (République démocratique)', + 'COG': 'Congo (République)', + 'COK': 'Îles Cook', + 'COL': 'Colombie', + 'COM': 'Comores', + 'CPV': 'Cap-Vert', + 'CRI': 'Costa Rica', + 'CUB': 'Cuba', + 'CUW': 'Curaçao', + 'CXR': 'Île Christmas', + 'CYM': 'Caimans', + 'CYP': 'Chypre', + 'CZE': 'Tchéquie', + 'DEU': 'Allemagne', + 'DJI': 'Djibouti', + 'DMA': 'Dominique', + 'DNK': 'Danemark', + 'DOM': 'République dominicaine', + 'DZA': 'Algérie', + 'ECU': 'Equateur', + 'EGY': 'Egypte', + 'ERI': 'Erythrée', + 'ESH': 'Sahara occidental', + 'ESP': 'Espagne', + 'EST': 'Estonie', + 'ETH': 'Ethiopie', + 'FIN': 'Finlande', + 'FJI': 'Fidji', + 'FLK': 'Îles Malouines', + 'FRA': 'France', + 'FRO': 'Féroé', + 'FSM': 'Micronésie', + 'GAB': 'Gabon', + 'GBR': 'Royaume-Uni', + 'GEO': 'Géorgie', + 'GGY': 'Guernesey', + 'GHA': 'Ghana', + 'GIB': 'Gibraltar', + 'GIN': 'Guinée', + 'GLP': 'Guadeloupe', + 'GMB': 'Gambie', + 'GNB': 'Guinée-Bissau', + 'GNQ': 'Guinée équatoriale', + 'GRC': 'Grèce', + 'GRD': 'Grenade', + 'GRL': 'Groenland', + 'GTM': 'Guatemala', + 'GUF': 'Guyane', + 'GUM': 'Guam', + 'GUY': 'Guyana', + 'HKG': 'Hong Kong', + 'HND': 'Honduras', + 'HRV': 'Croatie', + 'HTI': 'Haïti', + 'HUN': 'Hongrie', + 'IDN': 'Indonésie', + 'IMN': 'Île de Man', + 'IND': 'Inde', + 'IOT': "Territoire britannique de l'océan Indien", + 'IRL': 'Irlande', + 'IRN': 'Irak', + 'IRQ': 'Iran', + 'ISL': 'Islande', + 'ISR': 'Israël', + 'ITA': 'Italie', + 'JAM': 'Jamaïque', + 'JEY': 'Jersey', + 'JOR': 'Jordanie', + 'JPN': 'Japon', + 'KAZ': 'Kazakhstan', + 'KEN': 'Kenya', + 'KGZ': 'Kirghizistan', + 'KHM': 'Cambodge', + 'KIR': 'Kiribati', + 'KNA': 'Saint-Christophe-et-Niévès', + 'KOR': 'Corée du Sud', + 'KWT': 'Koweït', + 'LAO': 'Laos', + 'LBN': 'Liban', + 'LBR': 'Liberia', + 'LBY': 'Libye', + 'LCA': 'Sainte-Lucie', + 'LIE': 'Liechtenstein', + 'LKA': 'Sri Lanka', + 'LSO': 'Lesotho', + 'LTU': 'Lituanie', + 'LUX': 'Luxembourg', + 'LVA': 'Lettonie', + 'MAC': 'Macao', + 'MAF': 'Sint-Maarten', + 'MAR': 'Maroc', + 'MCO': 'Monaco', + 'MDA': 'Moldavie', + 'MDG': 'Madagascar', + 'MDV': 'Maldives', + 'MEX': 'Mexique', + 'MHL': 'Marshall', + 'MKD': 'Macedoine', + 'MLI': 'Mali', + 'MLT': 'Malte', + 'MMR': 'Birmanie', + 'MNE': 'Monténégro', + 'MNG': 'Mongolie', + 'MNP': 'Îles Mariannes du Nord', + 'MOZ': 'Mozambique', + 'MRT': 'Mauritanie', + 'MSR': 'Montserrat', + 'MTQ': 'Martinique', + 'MUS': 'Maurice', + 'MWI': 'Malawi', + 'MYS': 'Malaisie', + 'MYT': 'Mayotte', + 'NAM': 'Namibie', + 'NCL': 'Nouvelle-Calédonie', + 'NER': 'Niger', + 'NFK': 'Île Norfolk', + 'NGA': 'Nigeria', + 'NIC': 'Nicaragua', + 'NIU': 'Niue', + 'NLD': 'Pays-Bas', + 'NOR': 'Norvège', + 'NPL': 'Nepal', + 'NRU': 'Nauru', + 'NZL': 'Nouvelle-Zélande', + 'OMN': 'Oman', + 'PAK': 'Pakistan', + 'PAN': 'Panama', + 'PCN': 'Îles Pitcairn', + 'PER': 'Pérou', + 'PHL': 'Philippines', + 'PLW': 'Palaos', + 'PNG': 'Papouasie-Nouvelle-Guinée', + 'POL': 'Pologne', + 'PRI': 'Porto Rico', + 'PRK': 'Corée du Nord', + 'PRT': 'Portugal', + 'PRY': 'Paraguay', + 'PSE': 'Palestine', + 'PYF': 'Polynésie française', + 'QAT': 'Qatar', + 'REU': 'Réunion', + 'ROU': 'Roumanie', + 'RUS': 'Russie', + 'RWA': 'Rwanda', + 'SAU': 'Arabie saoudite', + 'SDN': 'Soudan', + 'SEN': 'Sénégal', + 'SGP': 'Singapour', + 'SGS': 'Georgie du Sud-et-les iles Sandwich du Sud', + 'SHN': 'Sainte-Hélène, Ascension et Tristan da Cunha', + 'SJM': 'Svalbard et île Jan Mayen', + 'SLB': 'Salomon', + 'SLE': 'Sierra Leone', + 'SLV': 'Salvador', + 'SMR': 'Saint-Marin', + 'SOM': 'Somalie', + 'SPM': 'Saint-Pierre-et-Miquelon', + 'SRB': 'Serbie', + 'SSD': 'Soudan du Sud', + 'STP': 'Sao Tomé-et-Principe', + 'SUR': 'Suriname', + 'SVK': 'Slovaquie', + 'SVN': 'Slovénie', + 'SWE': 'Suède', + 'SWZ': 'eSwatani', + 'SXM': 'Saint-Martin ', + 'SYC': 'Seychelles', + 'SYR': 'Syrie', + 'TCA': 'Îles Turques-et-Caïques', + 'TCD': 'Tchad', + 'TGO': 'Togo', + 'THA': 'Thaïlande', + 'TJK': 'Tadjikistan', + 'TKL': 'Tokelau', + 'TKM': 'Turkmenistan', + 'TLS': 'Timor oriental', + 'TON': 'Tonga', + 'TTO': 'Trinité-et-Tobago', + 'TUN': 'Tunisie', + 'TUR': 'Turquie', + 'TUV': 'Tuvalu', + 'TWN': 'Taiwan', + 'TZA': 'Tanzanie', + 'UGA': 'Ouganda', + 'UKR': 'Ukraine', + 'URY': 'Uruguay', + 'USA': 'Etats-Unis', + 'UZB': 'Ouzbékistan', + 'VAT': 'Saint-Siège (État de la Cité du Vatican)', + 'VCT': 'Saint-Vincent-et-les-Grenadines', + 'VEN': 'Venezuela', + 'VGB': 'Îles Vierges britanniques', + 'VIR': 'Îles Vierges des États-Unis', + 'VNM': 'Viêt Nam', + 'VUT': 'Vanuatu', + 'WLF': 'Wallis-et-Futuna', + 'WSM': 'Samoa', + 'XKX': 'Kosovo', + 'YEM': 'Yémen', + 'ZAF': 'Afrique du Sud', + 'ZMB': 'Zambie', + 'ZWE': 'Zimbabwe', + 'NTZ': 'Zone neutre', + 'UNO': 'Fonctionnaire des Nations Unies', + 'UNA': "Fonctionnaire d'une organisation affiliée aux Nations Unies", + 'UNK': 'Représentant des Nations Unies au Kosovo', + 'XXA': 'Apatride Convention 1954', + 'XXB': 'Réfugié Convention 1954', + 'XXC': 'Réfugié autre', + 'XXX': 'Résident Légal de Nationalité Inconnue', + 'D': 'Allemagne', + 'EUE': 'Union Européenne', + 'GBD': "Citoyen Britannique d'Outre-mer (BOTC)", + 'GBN': 'British National (Overseas)', + 'GBO': 'British Overseas Citizen', + 'GBP': 'British Protected Person', + 'GBS': 'British Subject', + 'XBA': 'Banque Africaine de Développement', + 'XIM': "Banque Africaine d'Export–Import", + 'XCC': 'Caribbean Community or one of its emissaries', + 'XCO': 'Common Market for Eastern and Southern Africa', + 'XEC': 'Economic Community of West African States', + 'XPO': 'International Criminal Police Organization', + 'XOM': 'Sovereign Military Order of Malta', + 'RKS': 'Kosovo', + 'WSA': 'World Service Authority World Passport' + } +} + +## 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 ?", +"Would you like to open the " +"log file ?" : "Would you like to open the log file ?", +"Starting..." : "Starting...", +"Informations about the current " +"document" : "Informations about the current document", +"IDLE" : "IDLE", +"Status" : "Status", +"Name" : "Name", +"Birth date" : "Birth date", +"Issue date" : "Issue date", +"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", +"Settings" : "Settings", +"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", + +"CHANGELOG" : "Version 3.1.1 \nMinor update with the following progressions: \n- Fixed a severe bug in the update system" + \ +"Version 3.1.0 \nMajor update with the following progressions: \n- Cosmetic modifications of the user interface \n- Stabilization of the changes made on the minor version 3.0 : user interface, OCR, VISA A and B, logging\n- Rationalization of the language system\n- Added update channels\n\n" + \ +"Version 3.0.8 final\nCorrection: bug in the update system'\n\n" + \ +"Version 3.0.6 \nMinor update with the following fixes:\n- Change in the appearance of the application launcher\n- Improvements to the interface, including stability\n- Added digital signature of the executable\n" + \ +"Version 3.0.7 final\nMajor update with the following corrections: \n- Redesign of the user interface\n- OCR function integrated into the application with TIFF and JPEG support\n- Corrections of errors on the processing of VISA type A and B, as well as residence permits\n\n" + \ +"Version 3.0.6 \nMinor update with the following fixes:\n- Change in the appearance of the application launcher\n- Improvements to the interface, including stability\n- Added digital signature of the executable\n" + \ +"Version 3.0.5 \n Minor update with the following corrections: \n- Change of executable icon to reflect the major version change accomplished in 3.0\n\n" + \ +"Version 3.0.4 \nMinor update with the following fixes:\n- Fixed a bug affecting the update system" + \ +"Version 3.0.3 \nMinor update with the following corrections: \n- Fixed a bug affecting the changelog\n- Fixed an error with the Delete Back key and Deleted causing a data loss" + \ +"Version 3.0.2 \nMinor update with the following corrections: \n- Change of executable icon\n- Fix of a bug affecting logging\n- Fix of a bug affecting document detection- And other minor modifications\n\n" + \ +"Version 3.0.1 \nMajor update with the following corrections: \n- Renewal of the executable's digital signature- Improvement of the log presentation in case of error\n- Total overhaul of the source code and disobfuscation\n- Reliable HTTPS downloads with checksum\n- New input terminals : a fast (731) and a complete one\n- Improved document detection, possibility of finer choice and the following regressions:\n- Temporary deletion of the OCR reading function. Planned return for a next version", + +"Document Review: {}\n\n" : "Document Review: {}\n\n", +"Checksum position {}: Lu {} VS " +"Calculated {} [facultative]\n" : "Checksum position {}: Read {} VS Calculated {} [facultative]\n", +"Checksum position {}: Lu {} VS " +"Calculated {}\n" : "Checksum position {}: Read {} VS Calculated {}\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 : {}", +"Update options" : "Update options", +"Language" : "Language", +"Show Changelog" : "Show the changelog", +"Please choose your language : " : "Please choose your language : ", +"Please choose your update " +"channel : " : "Please choose your update channel : ", +"Passeport" : "Passport", +"Carte-passeport" : "Passport card", +"Titre d'identité/de voyage" : "Identity/travel document", +"Certificat de membre d'équipage" : "Crew member certificate", +"Visa de type A" : "Type A visa", +"Visa de type B" : "Type B visa", +"Carte de séjour" : "Residence permit", +"Pièce d'identité/de voyage" : "Identity/travel document", +"Pièce d'identité FR" : "French Identity card", +"Permis de conduire" : "Driver License", + +"LANDCODE2" : { + "AW": "Aruba", + "AF": "Afghanistan", + "AO": "Angola", + "AI": "Anguilla", + "AL": "Albania", + "AD": "Andorra", + "AE": "United Arab Emirates", + "AR": "Argentina", + "AM": "Armenia", + "AS": "American Samoa", + "QA": "Antarctic", + "TF": 'French Southern and Antarctic Territories', + "AG": 'Antigua and Barbuda', + "TO": "Australia", + "AT": "Austria", + "AZ": "Azerbaidjan", + "BI": "Burundi", + "BE": "Belgium", + "BJ": "Benin", + "BQ": "Caribbean Netherlands", + "BF": "Burkina Faso", + "BD": "Bangladesh", + "BG": "Bulgaria", + "BH": "Bahrain", + "BS": "Bahamas", + "BA": "Bosnia and Herzegovina", + "BL": "Saint-Barthélemy", + "BY": "Belarus", + "BZ": "Belize", + "BM": "Bermuda", + "BO": "Bolivia", + "BR": 'Brazil', + "BB": "Barbados", + "BN": "Brunei", + "BT": "Bhutan", + "BW": "Botswana", + "CF": "Central African Republic", + "CA": "Canada", + "CC": "Cocos Islands", + "CH": "Switzerland", + "CL": "Chile", + "CN": "China", + "CI": "Côte d'Ivoire", + "CM": "Cameroon", + "CD": 'Congo (Democratic Republic)', + "CG": "Congo (Republic)", + "CK": "Cook Islands", + "CO": "Colombia", + "KM": "Comoros", + "CV": "Cape Verde", + "CR": "Costa Rica", + "CU": "Cuba", + "CW": "Curaçao", + "CX": "Christmas Island", + "KY": "Caimans", + "CY": "Cyprus", + "CZ": "Czech Republic", + "DE": "Germany", + "DJ": "Djibouti", + "DM": "Dominique", + "DK": "Denmark", + "DO": 'Dominican Republic', + "DZ": "Algeria", + "EC": "Ecuador", + "EG": "Egypt", + "ER": "Eritrea", + "EH": "Western Sahara", + "ES": "Spain", + "EE": "Estonia", + "AND": "Ethiopia", + "FI": "Finland", + "FJ": "Fiji", + "FK": "Falkland Islands", + "FR": "France", + "FO": "Faroese", + "FM": "Micronesia", + "GA": "Gabon", + "GB": "United Kingdom", + "GE": "Georgia", + "GG": "Guernsey", + "GH": "Ghana", + "GI": "Gibraltar", + "GN": "Guinea", + "GP": "Guadeloupe", + "GM": "Gambia", + "GW": "Guinea-Bissau", + "GQ": "Equatorial Guinea", + "GR": "Greece", + "GD": "Granada", + "GL": "Greenland", + "GT": "Guatemala", + "GF": "Guyana", + "GU": "Guam", + "GY": "Guyana", + "HK": "Hong Kong", + "HN": "Honduras", + "HR": "Croatia", + "HT": "Haiti", + "HU": "Hungary", + "ID": "Indonesia", + "IM": "Isle of Man", + "IN": "India", + "IO": 'British Indian Ocean Territory', + "IE": "Ireland", + "IR": "Iraq", + "IQ": "Iran", + "IS": "Iceland", + "IL": "Israel", + "IT": "Italy", + "JM": "Jamaica", + "I": "Jersey", + "JO": "Jordan", + "JP": "Japan", + "KZ": "Kazakhstan", + "KE": "Kenya", + "KG": "Kyrgyzstan", + "KH": "Cambodia", + "KI": "Kiribati", + "KN": "Saint Kitts and Nevis", + "KR": "South Korea", + "KW": "Kuwait", + "LA": "Laos", + "LB": "Lebanon", + "LR": "Liberia", + "LY": "Libya", + "LC": "Saint Lucia", + "LI": "Liechtenstein", + "LK": "Sri Lanka", + "LS": "Lesotho", + "LT": "Lithuania", + "LU": "Luxembourg", + "LV": "Latvia", + "MO": "Macao", + "MF": "Sint-Maarten", + "MA": "Morocco", + "MC": "Monaco", + "MD": 'Moldavia', + "MG": "Madagascar", + "MV": "Maldives", + "MX": "Mexico", + "MH": "Marshall", + "MK": "Macedonia", + "ML": "Mali", + "MT": "Malta", + "MM": "Burma", + "ME": "Montenegro", + "MN": "Mongolia", + "MP": "Northern Mariana Islands", + "MZ": "Mozambique", + "MR": "Mauritania", + "MS": "Montserrat", + "MQ": "Martinique", + "MU": "Mauritius", + "MW": "Malawi", + "MY": "Malaysia", + "YT": "Mayotte", + "NA": "Namibia", + "NC": "New Caledonia", + "NE": "Niger", + "NF": "Norfolk Island", + "NG": "Nigeria", + "NI": "Nicaragua", + "NU": "Niue", + "NL": 'Netherlands', + "NO": "Norway", + "NP": "Nepal", + "NR": "Nauru", + "NZ": "New Zealand", + "OM": "Oman", + "PK": "Pakistan", + "PA": "Panama", + "NP": "Pitcairn Islands", + "PE": "Peru", + "PH": "Philippines", + "PW": "Palau", + "PG": "Papua New Guinea", + "PL": "Poland", + "PR": "Puerto Rico", + "KP": "North Korea", + "PT": "Portugal", + "PY": "Paraguay", + "PS": "Palestine", + "FP": "French Polynesia", + "QA": "Qatar", + "RE": "Reunion", + "RO": "Romania", + "RU": "Russia", + "RW": "Rwanda", + "SA": "Saudi Arabia", + "SD": "Sudan", + "SN": "Senegal", + "SG": "Singapore", + "GS": "South Georgia and the South Sandwich Islands", + 'SH': 'St Helena, Ascension and Tristan da Cunha', + "SJ": "Svalbard and Jan Mayen Island", + "SB": "Solomon", + "SL": "Sierra Leone", + "SV": "El Salvador", + "SM": "San Marino", + "SO": "Somalia", + "PM": "Saint-Pierre-et-Miquelon", + "RS": "Serbia", + "SS": "South Sudan", + "ST": "Sao Tome and Principe", + "SR": "Suriname", + "SK": "Slovakia", + "SI": "Slovenia", + "SE": "Sweden", + "SZ": "eSwatani", + "SX": "Saint-Martin", + "SC": "Seychelles", + "SY": "Syria", + "TC": "Turks and Caicos Islands", + "TD": "Chad", + "TG": "Togo", + "TH": "Thailand", + "TJ": "Tajikistan", + "TK": "Tokelau", + "TM": "Turkmenistan", + "TL": "East Timor", + "TO": "Tonga", + "TT": "Trinidad and Tobago", + "TN": "Tunisia", + "TR": "Turkey", + "TV": "Tuvalu", + "TW": "Taiwan", + "TZ": "Tanzania", + "UG": "Uganda", + "UA": "Ukraine", + "UY": "Uruguay", + "US": "United States", + "UZ": "Uzbekistan", + 'VA': 'Holy See (Vatican City State)', + 'VC': 'Saint Vincent and the Grenadines', + "EV": "Venezuela", + "VG": "British Virgin Islands", + 'VI': 'Virgin Islands of the United States', + "VN": "Vietnam", + "VU": "Vanuatu", + "WF": "Wallis and Futuna", + 'WS': 'Samoa', + "XK": "Kosovo", + "YE": "Yemen", + "ZA": "South Africa", + "ZM": "Zambia", + "ZW": "Zimbabwe" + }, + +"LANDCODE3" : { + "ABW": "Aruba", + "AFG": "Afghanistan", + "OGM": "Angola", + "AIA": "Anguilla", + 'ALB': 'Albania', + "AND": "Andorra", + "AER": "United Arab Emirates", + "ARG": "Argentina", + "ARM": "Armenia", + "ASM": "American Samoa", + "ATA": "Antarctica", + 'ATF': 'French Southern and Antarctic Lands', + "ATG": "Antigua and Barbuda", + "AUS": "Australia", + "AUT": "Austria", + "AZE": "Azerbaidjan", + "BDI": "Burundi", + "BEL": "Belgium", + "BEN": "Benin", + 'BES': 'Caribbean Netherlands', + "BFA": "Burkina Faso", + "BGD": "Bangladesh", + "BGR": "Bulgaria", + "BHR": "Bahrain", + "BHS": "Bahamas", + "BIH": "Bosnia and Herzegovina", + "BLM": "Saint-Barthélemy", + "BLR": "Belarus", + "BLZ": "Belize", + "BMU": "Bermuda", + "BOL": "Bolivia", + "BRA": "Brazil", + 'BRB': 'Barbados', + "BRN": "Brunei", + "BTN": "Bhutan", + "BWA": "Botswana", + 'CAF': 'Central African Republic', + 'CAN': 'Canada', + "CCK": "Cocos Islands", + "CHE": "Switzerland", + "CHL": "Chile", + "CHN": "China", + 'CIV': "Côte d'Ivoire", + "CMR": "Cameroon", + 'COD': 'Congo (Democratic Republic)', + "COG": "Congo (Republic)", + "COK": "Cook Islands", + "COL": "Colombia", + "COM": "Comoros", + 'CPV': 'Cape Verde', + "CRI": "Costa Rica", + "CUB": "Cuba", + "CUW": "Curaçao", + "CXR": "Christmas Island", + "CYM": "Caimans", + "CYP": "Cyprus", + "CZE": "Czech Republic", + "DEU": "Germany", + "DJI": "Djibouti", + "DMA": "Dominique", + "DNK": "Denmark", + "DOM": "Dominican Republic", + "DZA": "Algeria", + 'ECU': 'Ecuador', + "EGY": "Egypt", + "ERI": "Eritrea", + 'ESH': 'Western Sahara', + "ESP": "Spain", + "EST": "Estonia", + "ETH": "Ethiopia", + "FIN": "Finland", + "FJI": "Fiji", + "FLK": "Falkland Islands", + "FRA": "France", + "FRO": "Faroese", + "WSF": "Micronesia", + "ATM": "Gabon", + "GBR": "United Kingdom", + "GEO": "Georgia", + "GGY": "Guernsey", + "GHA": "Ghana", + "GIB": "Gibraltar", + "GIN": "Guinea", + "GLP": "Guadeloupe", + "GMB": "Gambia", + "GNB": "Guinea-Bissau", + "GNQ": "Equatorial Guinea", + "GRC": "Greece", + "DSO": "Granada", + "GRL": "Greenland", + "GTM": "Guatemala", + 'GUF': 'Guyana', + "GUM": "Guam", + "GUY": "Guyana", + "HKG": "Hong Kong", + "HND": "Honduras", + "HRV": "Croatia", + "HTI": "Haiti", + "HUN": "Hungary", + "IDN": "Indonesia", + "IMN": "Isle of Man", + "IND": "India", + 'IOT': 'British Indian Ocean Territory', + "IRL": "Ireland", + "IRN": "Iraq", + "IRQ": "Iran", + "ISL": "Iceland", + "SRI": "Israel", + "ITA": "Italy", + "JAM": "Jamaica", + "JEY": "Jersey", + "JOR": "Jordan", + 'JPN': 'Japan', + "KAZ": "Kazakhstan", + "KEN": "Kenya", + "KGZ": "Kyrgyzstan", + "KHM": "Cambodia", + "KIR": "Kiribati", + "KNA": "Saint Kitts and Nevis", + "KOR": "South Korea", + "KWT": "Kuwait", + "LAO": "Laos", + "LBN": "Lebanon", + "LBR": "Liberia", + "LBY": "Libya", + "LCA": "Saint Lucia", + "LEL": "Liechtenstein", + "LKA": "Sri Lanka", + "LSO": "Lesotho", + "LTU": "Lithuania", + "LUX": "Luxembourg", + "LVA": "Latvia", + "MAC": "Macao", + "MAF": "Sint-Maarten", + "MAR": "Morocco", + "MCO": "Monaco", + "MDA": "Moldavia", + "MDG": "Madagascar", + "MDV": "Maldives", + "MEX": "Mexico", + "MHL": "Marshall", + "MKD": "Macedonia", + "MLI": "Mali", + "MLT": "Malta", + "MMR": "Burma", + "MNE": "Montenegro", + "MNG": "Mongolia", + 'MNP': 'Northern Mariana Islands', + "MOZ": "Mozambique", + "MRT": "Mauritania", + "MSR": "Montserrat", + "MTQ": "Martinique", + "MUS": "Mauritius", + "MWI": "Malawi", + "MYS": "Malaysia", + "MYT": "Mayotte", + "NAM": "Namibia", + "NCL": "New Caledonia", + "NER": "Niger", + "NFK": "Norfolk Island", + "NGA": "Nigeria", + "NIC": "Nicaragua", + "NIU": "Niue", + 'NLD': 'Netherlands', + "NOR": "Norway", + "NPL": "Nepal", + "NRU": "Nauru", + "NZL": "New Zealand", + "OMN": "Oman", + "PAK": "Pakistan", + "PAN": "Panama", + "PCN": "Pitcairn Islands", + "PER": "Peru", + "PHL": "Philippines", + "PLW": "Palau", + "PNG": "Papua New Guinea", + "POL": "Poland", + "PRI": "Puerto Rico", + "PRK": "North Korea", + "PRT": "Portugal", + "PRY": "Paraguay", + "PES": "Palestine", + "PYF": "French Polynesia", + "QAT": "Qatar", + "REU": "Reunion", + "ROU": "Romania", + "RUS": "Russia", + "RWA": "Rwanda", + "UAA": "Saudi Arabia", + "SDN": "Sudan", + "SEN": "Senegal", + "SGP": "Singapore", + 'SGS': 'South Georgia and the South Sandwich Islands', + "SHN": "St Helena, Ascension and Tristan da Cunha", + "SJM": "Svalbard and Jan Mayen Island", + "SLB": "Solomon", + "SLE": "Sierra Leone", + "SLV": "El Salvador", + "SMR": "San Marino", + "SOM": "Somalia", + "SPM": "Saint-Pierre-et-Miquelon", + "SRB": "Serbia", + "SSD": "South Sudan", + "PTS": "Sao Tome and Principe", + "SUR": "Suriname", + "SVK": "Slovakia", + "SVN": "Slovenia", + "SWE": "Sweden", + "SWZ": "eSwatani", + "SXM": "Saint-Martin", + "SYC": "Seychelles", + "SYR": "Syria", + "TCA": "Turks and Caicos Islands", + "TCD": "Chad", + "TGO": "Togo", + "THA": "Thailand", + "TJK": "Tajikistan", + "TKL": "Tokelau", + "TKM": "Turkmenistan", + "TLS": "East Timor", + "TON": "Tonga", + 'TTO': 'Trinidad and Tobago', + "TUN": "Tunisia", + "TUR": "Turkey", + "TUV": "Tuvalu", + "TWN": "Taiwan", + "TZA": "Tanzania", + "UGA": "Uganda", + "UKR": "Ukraine", + "URY": "Uruguay", + "USA": "United States", + "UZB": "Uzbekistan", + 'VAT': 'Holy See (Vatican City State)', + 'VCT': 'Saint Vincent and the Grenadines', + "VEN": "Venezuela", + 'VGB': 'British Virgin Islands', + 'VIR': 'Virgin Islands of the United States', + "VNM": "Vietnam", + "STV": "Vanuatu", + "WLF": "Wallis and Futuna", + "WSM": "Samoa", + "XKX": "Kosovo", + "YEM": "Yemen", + "ZAF": "South Africa", + "ZMB": "Zambia", + "ZWE": "Zimbabwe", + 'NTZ': 'Neutral Zone', + 'UNO': 'United Nations official', + 'UNA': "Staff member of a United Nations-affiliated organization", + 'UNK': 'United Nations Representative in Kosovo', + 'XXA': 'Stateless Person 1954 Convention', + "XXB": "Refugee Convention 1954", + "XXC": "Other refugee", + 'XXX': 'Legal Resident of Unknown Nationality', + 'D' : 'Germany', + "EUE": "European Union", + "GBD": "British Overseas Citizen (BOTC)", + "GBN": "British National (Overseas)", + "GBO": "British Overseas Citizen", + 'GBP': 'British Protected Person', + "GBS": "British Subject", + 'XBA': 'African Development Bank', + 'XIM': "African Export Import Bank", + 'XCC':' Caribbean Community or one of its emissaries', + 'XCO': 'Common Market for Eastern and Southern Africa', + 'XEC': 'Economic Community of West African States', + 'XPO': 'International Criminal Police Organization', + 'XOM': 'Sovereign Military Order of Malta', + "RKS": "Kosovo", + "WSA": "World Service Authority World Passport" + } +} + +## MAIN DICT +all = \ +{ +"fr" : french, +"en" : english +} + + +## Functions + +def readLang(): + + if os.path.isfile(globs.CNIRLangFile): + with open(globs.CNIRLangFile, 'r') as (configFile): + try: + # Reading it + globs.CNIRlang = configFile.read() + except Exception as e: + critical.crashCNIR() + raise IOError(str(e)) + else: + # Recreating the url file + try: + os.mkdir(globs.CNIRFolder + '\\config') + except: + pass + + with open(globs.CNIRLangFile, 'w') as (configFile): + try: + # Writing it + configFile.write(globs.CNIRlang) + except Exception as e: + critical.crashCNIR() + raise IOError(str(e)) + +def updateLang(choice): + + if os.path.isfile(globs.CNIRLangFile): + with open(globs.CNIRLangFile, 'w') as (configFile): + try: + # Writing it + globs.CNIRlang = choice + configFile.write(choice) + except Exception as e: + critical.crashCNIR() + raise IOError(str(e)) + else: + # Recreating the url file + try: + os.mkdir(globs.CNIRFolder + '\\config') + except: + pass + + with open(globs.CNIRLangFile, 'w') as (configFile): + try: + # Writing it + configFile.write(globs.CNIRlang) + except Exception as e: + critical.crashCNIR() + raise IOError(str(e)) \ No newline at end of file diff --git a/src/launcher.py b/src/launcher.py index 3edcfaa..116c642 100644 --- a/src/launcher.py +++ b/src/launcher.py @@ -26,12 +26,13 @@ import sys import os import threading -import traceback +import critical # critical.py 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 +45,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/logger.py b/src/logger.py index 1e1d00f..9fea829 100644 --- a/src/logger.py +++ b/src/logger.py @@ -26,6 +26,7 @@ import logging import os +import critical # critical.py import globs # globs.py ## The logging class diff --git a/src/main.py b/src/main.py index b921838..6e0f54f 100644 --- a/src/main.py +++ b/src/main.py @@ -31,29 +31,37 @@ from tkinter import filedialog from tkinter import ttk import threading from datetime import datetime +from importlib import reload import re -import traceback import cv2 import PIL.Image, PIL.ImageTk import os, shutil import webbrowser +import sys, os +import critical # critical.py 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 class mainWindow(Tk): + ## App Pattern + def __init__(self): Tk.__init__(self) self.initialize() def initialize(self): + """ + Initializes the main window + """ self.mrzChar = "" self.mrzDecided = False self.Tags = [] @@ -61,6 +69,12 @@ class mainWindow(Tk): self.corners = [] self.validatedtext = "" + # The icon + if getattr(sys, 'frozen', False): + self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico') + else: + self.iconbitmap('id-card.ico') + # Hide during construction self.withdraw() @@ -70,15 +84,16 @@ class mainWindow(Tk): logfile.printdbg('Launching main window with resolution' + str(ws) + 'x' + str(hs)) # Configuring the size of each part of the window - self.grid_columnconfigure(0, weight=1, minsize=(ws / 2 * 0.3333333333333333)) - self.grid_columnconfigure(1, weight=1, minsize=(ws / 2 * 0.3333333333333333)) + self.grid_columnconfigure(0, minsize=(ws / 2 * 0.3333333333333333)) + self.grid_columnconfigure(1, minsize=(ws / 2 * 0.3333333333333333)) self.grid_columnconfigure(2, weight=1, minsize=(ws / 2 * 0.3333333333333333)) - self.grid_rowconfigure(0, weight=1, minsize=(hs / 2 * 0.5)) - self.grid_rowconfigure(1, weight=1, minsize=(hs / 2 * 0.10)) - self.grid_rowconfigure(2, weight=1, minsize=(hs / 2 * 0.35)) + self.grid_rowconfigure(0, minsize=(hs / 2 * 0.5)) + self.grid_rowconfigure(1, minsize=(hs / 2 * 0.10)) + self.grid_rowconfigure(2, minsize=(hs / 2 * 0.35)) + self.grid_rowconfigure(3, minsize=10) # 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) @@ -90,52 +105,57 @@ class mainWindow(Tk): self.lecteur_ci.grid_rowconfigure(3, weight=1) self.lecteur_ci.grid_rowconfigure(4, weight=1) self.lecteur_ci.grid_rowconfigure(5, weight=1) + + # And what about the status bar ? + self.statusbar = ihm.StatusBar(self) + self.statusbar.grid(row=3, columnspan=3, sticky="NSEW") # 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.statusbar.set(lang.all[globs.CNIRlang]["IDLE"]) + 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 +173,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 +278,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 +292,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 +314,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,41 +333,45 @@ 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) + menu2 = Menu(menubar, tearoff=0) + menu2.add_command(label=lang.all[globs.CNIRlang]["Update options"], command=(self.updateSet)) + menu2.add_command(label=lang.all[globs.CNIRlang]["Show Changelog"], command=(self.showChangeLog)) + menu2.add_separator() + menu2.add_command(label=lang.all[globs.CNIRlang]["Language"], command=(self.languageSet)) + menubar.add_cascade(label=lang.all[globs.CNIRlang]["Settings"], menu=menu2) 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) + menubar.add_command(label="<|>", command=(self.panelResize)) self.config(menu=menubar) - + # The title self.wm_title(globs.CNIRName) - # The icon - if getattr(sys, 'frozen', False): - self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico') - else: - self.iconbitmap('id-card.ico') - # Make this window resizable and set her size - self.resizable(width=True, height=True) + self.resizable(0, 0) self.update() - w = int(self.winfo_reqwidth()) - h = int(self.winfo_reqheight()) - ws = self.winfo_screenwidth() - hs = self.winfo_screenheight() - x = (ws - w)/2 - y = (hs - h)/2 - self.geometry('%dx%d+%d+%d' % (w, h, x, y)) + self.w = int(self.winfo_reqwidth()) + self.h = int(self.winfo_reqheight()) + self.ws = self.winfo_screenwidth() + self.hs = self.winfo_screenheight() + self.x = (self.ws - self.w)/2 + self.y = (self.hs - self.h)/2 + self.geometry('%dx%d+%d+%d' % (self.w, self.h, self.x, self.y)) self.update() self.deiconify() - self.minsize(self.winfo_width(), self.winfo_height()) + self.attributes("-topmost", 1) + self.maxsize(self.w, self.h) + self.minsize(int(2.15 * (self.ws / 2 * 0.3333333333333333)), self.h) + self.currentw = self.w # Set image self.imageViewer.image = None @@ -364,27 +388,33 @@ class mainWindow(Tk): self.imageViewer.ZONE.bind("", self.rectangleSelectScan) logfile.printdbg('Initialization successful') - - def statusUpdate(self, image=None, setplace=False): - if image: - self.imageViewer.image = image - self.imageViewer.ZONE.itemconfigure(self.STATUSimg, image=(self.imageViewer.image)) - self.imageViewer.ZONE.configure(scrollregion=self.imageViewer.ZONE.bbox("all")) + if globs.CNIROpenFile: + self.after_idle(lambda : self.openScanFile(sys.argv[1])) + + + ## OCR related functions + def rectangleSelectScan(self, event): + """ + Realises the selection of the MRZ to make OCR possible + """ 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) def goOCRDetection(self): + """ + Realises the OCR detection and get the text in self.mrzChar (and prints it) + """ if self.imageViewer.image: cv_img = cv2.imreadmulti(self.imageViewer.imagePath)[1][self.imageViewer.pagenumber] cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB) @@ -434,7 +464,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 +475,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,16 +483,20 @@ 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) + ## Regex and document detection + control related functions + def stringValidation(self, keysym): + """ + Analysis of the already typed document + """ # analysis # If we must decide the type of the document if not self.mrzDecided: @@ -478,11 +512,13 @@ 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.statusbar.set(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.statusbar.set(candidates[0][2]) self.mrzDecided = candidates[0] else: # corrects some problems @@ -569,11 +605,13 @@ 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.statusbar.set(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.statusbar.set(candidates[0][2]) self.mrzDecided = candidates[0] return "break" @@ -583,7 +621,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] @@ -625,35 +663,147 @@ class mainWindow(Tk): char = self.speed731text.get() self.speedResultPrint(str(mrz.computeControlSum(char))) return "break" + + def computeSigma(self): + """ + Launch the checksum computation, infos validation and print/display the results + """ + # the regex + regex = re.compile("[^A-Z0-9<]") + code = re.sub(regex, '', self.mrzChar) + self.compliance = True + allSums = mrz.computeAllControlSum(self.mrzDecided, code)["ctrlSumList"] + #print("Code : _{}_ | Sums : {}".format(code, allSums)) + + self.termtext.tag_remove("conforme", "1.0", "end") + self.termtext.tag_remove("nonconforme", "1.0", "end") + + self.clearTerm() + 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 + y = sum[1] % len(self.mrzDecided[0][0]) + #print("index : {}.{}".format(x,y)) + #print("{} == {}".format(code[sum[1]], sum[2])) + + if sum[3]: + self.logOnTerm(lang.all[globs.CNIRlang]["Checksum position {}: Lu {} VS Calculated {} [facultative]\n"].format(sum[1], code[sum[1]], sum[2])) + else: + self.logOnTerm(lang.all[globs.CNIRlang]["Checksum position {}: Lu {} VS Calculated {}\n"].format(sum[1], code[sum[1]], sum[2])) + + # if sum is facultative or if sum is ok + try: + if sum[3] or int(code[sum[1]]) == int(sum[2]): + self.termtext.tag_add("conforme", "{}.{}".format(x,y), "{}.{}".format(x,y+1)) + self.termtext.tag_configure("conforme", background="green", foreground="white") + else: + self.termtext.tag_add("nonconforme", "{}.{}".format(x,y), "{}.{}".format(x,y+1)) + self.termtext.tag_configure("nonconforme", background="red", relief='raised', foreground="white") + self.compliance = False + except ValueError: + self.termtext.tag_add("nonconforme", "{}.{}".format(x,y), "{}.{}".format(x,y+1)) + self.termtext.tag_configure("nonconforme", background="red", relief='raised', foreground="white") + self.compliance = False + + # get the infos + docInfos = mrz.getDocInfos(self.mrzDecided, code) + #print(docInfos) + # display the infos + for key in [ e for e in docInfos ]: + #print(docInfos[key]) + if key in ["CODE", "CTRL", "CTRLF"]: + continue + if not docInfos[key] == False: + self.infoList[key]['text'] = docInfos[key] + self.infoList[key]['background'] = self['background'] + self.infoList[key]['foreground'] = "black" + else: + self.infoList[key]['background'] = "red" + self.infoList[key]['foreground'] = "white" + self.infoList[key]['text'] = "NC" + self.compliance = False + + if self.compliance == True: + self.STATUStxt["text"] = lang.all[globs.CNIRlang]["COMPLIANT"] + self.STATUStxt["foreground"] = "green" + self.statusbar.set(lang.all[globs.CNIRlang]["COMPLIANT"]) + else: + self.STATUStxt["text"] = lang.all[globs.CNIRlang]["IMPROPER"] + self.STATUStxt["foreground"] = "red" + self.statusbar.set(lang.all[globs.CNIRlang]["IMPROPER"]) + + ## Print functions + def logOnTerm(self, text): + """ + Writes on the monitor + """ self.monlog['state'] = 'normal' self.monlog.insert('end', text) self.monlog['state'] = 'disabled' self.monlog.yview(END) def clearTerm(self): + """ + Clears the monitor + """ self.monlog['state'] = 'normal' self.monlog.delete('1.0', 'end') self.monlog['state'] = 'disabled' self.monlog.yview(END) def speedResultPrint(self, text): + """ + Prints a result in the quick entry terminal + """ self.speedResult['state'] = 'normal' self.speedResult.delete("1.0", 'end') self.speedResult.insert('end', text) self.speedResult['state'] = 'disabled' + ## Document display related functions + + def DisplayUpdate(self, image=None, setplace=False): + """ + Reload the displayer to display the image or not + """ + if image: + self.imageViewer.image = image + self.imageViewer.ZONE.itemconfigure(self.STATUSimg, image=(self.imageViewer.image)) + self.imageViewer.ZONE.configure(scrollregion=self.imageViewer.ZONE.bbox("all")) + def goPageChoice(self, event): + """ + Change the current viewed page of the multipage tiff if needed + """ self.imageViewer.pagenumber = int(self.toolbar.pageChooser.get()) - 1 self.resizeScan() def openingScan(self): + """ + Open the scan, ask its path and displays it + """ 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): + """ + Open an image file at path to display it on the displayer + """ + # 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 +835,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.DisplayUpdate(photo) def zoomInScan50(self, quantity = 50): if self.imageViewer.image: @@ -746,6 +896,9 @@ class mainWindow(Tk): self.resizeScan() def negativeScan(self): + """ + Invert the bits to make a negative of the scan (and highlight the contrasts) + """ if self.imageViewer.image: # Load an image using OpenCV cv_img = cv2.imreadmulti(self.imageViewer.imagePath)[1][self.imageViewer.pagenumber] @@ -760,6 +913,9 @@ class mainWindow(Tk): self.resizeScan(cv_img) def resizeScan(self, cv_img = None): + """ + Reloads the image according to settings + """ if self.imageViewer.image: try: if not hasattr(cv_img, 'shape'): @@ -789,10 +945,10 @@ class mainWindow(Tk): cv_img = cv2.resize(cv_img, dim, interpolation = cv2.INTER_AREA) # 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.DisplayUpdate( photo) except Exception as e: logfile.printerr("Error with opencv : {}".format(e)) - traceback.print_exc(file=sys.stdout) + critical.crashCNIR() try: # Reload an image using OpenCV path = self.imageViewer.imagePath @@ -807,144 +963,97 @@ class mainWindow(Tk): height, width, channels_no = cv_img.shape # 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.DisplayUpdate(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") + critical.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() + ## IHM and user interface related functions + def newEntry(self): + """ + Reinits the IHM and invite + """ 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): + """ + Shows the About dialog + """ 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): + """ + Shows the keyboard help summary + """ 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") + """ + Opens the Github Issue Repository page + """ + webbrowser.open_new("https://github.com/neox95/CNIRevelator/issues") - def openBrowser(self, url): - webbrowser.open_new(url) + def showChangeLog(self): + changelogWin = ihm.ChangelogDialog(self, ('{} : CNIRevelator {}\n\n{}'.format(lang.all[globs.CNIRlang]["Program version"], globs.verstring_full, lang.all[globs.CNIRlang]["CHANGELOG"]))) + changelogWin.transient(self) + changelogWin.grab_set() + changelogWin.focus_force() + self.wait_window(changelogWin) - def computeSigma(self): + def updateSet(self): """ - Launch the checksum computation, infos validation and display the results + Update Settings """ - # the regex - regex = re.compile("[^A-Z0-9<]") - code = re.sub(regex, '', self.mrzChar) - self.compliance = True - - allSums = mrz.computeAllControlSum(self.mrzDecided, code)["ctrlSumList"] - #print("Code : _{}_ | Sums : {}".format(code, allSums)) - - self.termtext.tag_remove("conforme", "1.0", "end") - self.termtext.tag_remove("nonconforme", "1.0", "end") - - self.clearTerm() - self.logOnTerm("Examen du document : {}\n\n".format(self.mrzDecided[2])) - - for sum in allSums: - x = sum[1] // len(self.mrzDecided[0][0]) +1 - y = sum[1] % len(self.mrzDecided[0][0]) - #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])) - - # if sum is facultative or if sum is ok - try: - if sum[3] or int(code[sum[1]]) == int(sum[2]): - self.termtext.tag_add("conforme", "{}.{}".format(x,y), "{}.{}".format(x,y+1)) - self.termtext.tag_configure("conforme", background="green", foreground="white") - else: - self.termtext.tag_add("nonconforme", "{}.{}".format(x,y), "{}.{}".format(x,y+1)) - self.termtext.tag_configure("nonconforme", background="red", relief='raised', foreground="white") - self.compliance = False - except ValueError: - self.termtext.tag_add("nonconforme", "{}.{}".format(x,y), "{}.{}".format(x,y+1)) - self.termtext.tag_configure("nonconforme", background="red", relief='raised', foreground="white") - self.compliance = False - - # get the infos - docInfos = mrz.getDocInfos(self.mrzDecided, code) - #print(docInfos) - # display the infos - for key in [ e for e in docInfos ]: - #print(docInfos[key]) - if key in ["CODE", "CTRL"]: - continue - if not docInfos[key] == False: - self.infoList[key]['text'] = docInfos[key] - self.infoList[key]['background'] = self['background'] - self.infoList[key]['foreground'] = "black" - else: - self.infoList[key]['background'] = "red" - self.infoList[key]['foreground'] = "white" - self.infoList[key]['text'] = "NC" - self.compliance = False - - if self.compliance == True: - self.STATUStxt["text"] = "CONFORME" - self.STATUStxt["foreground"] = "green" + changeupdateWin = ihm.updateSetDialog(self) + changeupdateWin.transient(self) + changeupdateWin.grab_set() + changeupdateWin.focus_force() + self.wait_window(changeupdateWin) + + def languageSet(self): + """ + Lang Settings + """ + changelangWin = ihm.langDialog(self) + changelangWin.transient(self) + changelangWin.grab_set() + changelangWin.focus_force() + self.wait_window(changelangWin) + + global mrz + mrz = reload(mrz) + + self.initialize() + + def panelResize(self): + """ + Shows or hides the panel + """ + if self.currentw > int(2.15 * (self.ws / 2 * 0.3333333333333333)): + self.currentw = int(2.15 * (self.ws / 2 * 0.3333333333333333)) + self.geometry('%dx%d+%d+%d' % (self.currentw, self.h, self.x, self.y)) + self.update() else: - self.STATUStxt["text"] = "NON CONFORME" - self.STATUStxt["foreground"] = "red" - - return - - - - - + self.currentw = self.w + self.geometry('%dx%d+%d+%d' % (self.currentw, self.h, self.x, self.y)) + self.update() diff --git a/src/mrz.py b/src/mrz.py index e51fad6..ace7a69 100644 --- a/src/mrz.py +++ b/src/mrz.py @@ -24,537 +24,22 @@ ******************************************************************************** """ -import re -import logger # logger.py import re import datetime +import logger # logger.py +import globs # globs.py +import lang # lang.py +import critical # critical.py + ## SEX CODES sexcode = {'M':'Homme', 'F':'Femme', 'X':'Non spécifié'} ## COUNTRY CODES -landcode2 = { - 'AW': 'Aruba', - 'AF': 'Afghanistan', - 'AO': 'Angola', - 'AI': 'Anguilla', - 'AL': 'Albanie', - 'AD': 'Andorre', - 'AE': 'Emirats arabes unis', - 'AR': 'Argentine', - 'AM': 'Arménie', - 'AS': 'Samoa américaines', - 'AQ': 'Antarctique', - 'TF': 'Terres australes et antarctiques françaises', - 'AG': 'Antigua-et-Barbuda', - 'AU': 'Australie', - 'AT': 'Autriche', - 'AZ': 'Azerbaidjan', - 'BI': 'Burundi', - 'BE': 'Belgique', - 'BJ': 'Benin', - 'BQ': 'Pays-Bas caribéens', - 'BF': 'Burkina Faso', - 'BD': 'Bangladesh', - 'BG': 'Bulgarie', - 'BH': 'Bahrein', - 'BS': 'Bahamas', - 'BA': 'Bosnie-Herzegovine', - 'BL': 'Saint-Barthélemy', - 'BY': 'Bielorussie', - 'BZ': 'Belize', - 'BM': 'Bermudes', - 'BO': 'Bolivie', - 'BR': 'Brésil', - 'BB': 'Barbade', - 'BN': 'Brunei', - 'BT': 'Bhoutan', - 'BW': 'Botswana', - 'CF': 'République Centrafricaine', - 'CA': 'Canada', - 'CC': 'Îles Cocos', - 'CH': 'Suisse', - 'CL': 'Chili', - 'CN': 'Chine', - 'CI': "Côte d'Ivoire", - 'CM': 'Cameroun', - 'CD': 'Congo (République démocratique)', - 'CG': 'Congo (République)', - 'CK': 'Îles Cook', - 'CO': 'Colombie', - 'KM': 'Comores', - 'CV': 'Cap-Vert', - 'CR': 'Costa Rica', - 'CU': 'Cuba', - 'CW': 'Curaçao', - 'CX': 'Île Christmas', - 'KY': 'Caimans', - 'CY': 'Chypre', - 'CZ': 'Tchéquie', - 'DE': 'Allemagne', - 'DJ': 'Djibouti', - 'DM': 'Dominique', - 'DK': 'Danemark', - 'DO': 'République dominicaine', - 'DZ': 'Algérie', - 'EC': 'Equateur', - 'EG': 'Egypte', - 'ER': 'Erythrée', - 'EH': 'Sahara occidental', - 'ES': 'Espagne', - 'EE': 'Estonie', - 'ET': 'Ethiopie', - 'FI': 'Finlande', - 'FJ': 'Fidji', - 'FK': 'Îles Malouines', - 'FR': 'France', - 'FO': 'Féroé', - 'FM': 'Micronésie', - 'GA': 'Gabon', - 'GB': 'Royaume-Uni', - 'GE': 'Géorgie', - 'GG': 'Guernesey', - 'GH': 'Ghana', - 'GI': 'Gibraltar', - 'GN': 'Guinée', - 'GP': 'Guadeloupe', - 'GM': 'Gambie', - 'GW': 'Guinée-Bissau', - 'GQ': 'Guinée équatoriale', - 'GR': 'Grèce', - 'GD': 'Grenade', - 'GL': 'Groenland', - 'GT': 'Guatemala', - 'GF': 'Guyane', - 'GU': 'Guam', - 'GY': 'Guyana', - 'HK': 'Hong Kong', - 'HN': 'Honduras', - 'HR': 'Croatie', - 'HT': 'Haïti', - 'HU': 'Hongrie', - 'ID': 'Indonésie', - 'IM': 'Île de Man', - 'IN': 'Inde', - 'IO': "Territoire britannique de l'océan Indien", - 'IE': 'Irlande', - 'IR': 'Irak', - 'IQ': 'Iran', - 'IS': 'Islande', - 'IL': 'Israël', - 'IT': 'Italie', - 'JM': 'Jamaïque', - 'JE': 'Jersey', - 'JO': 'Jordanie', - 'JP': 'Japon', - 'KZ': 'Kazakhstan', - 'KE': 'Kenya', - 'KG': 'Kirghizistan', - 'KH': 'Cambodge', - 'KI': 'Kiribati', - 'KN': 'Saint-Christophe-et-Niévès', - 'KR': 'Corée du Sud', - 'KW': 'Koweït', - 'LA': 'Laos', - 'LB': 'Liban', - 'LR': 'Liberia', - 'LY': 'Libye', - 'LC': 'Sainte-Lucie', - 'LI': 'Liechtenstein', - 'LK': 'Sri Lanka', - 'LS': 'Lesotho', - 'LT': 'Lituanie', - 'LU': 'Luxembourg', - 'LV': 'Lettonie', - 'MO': 'Macao', - 'MF': 'Sint-Maarten', - 'MA': 'Maroc', - 'MC': 'Monaco', - 'MD': 'Moldavie', - 'MG': 'Madagascar', - 'MV': 'Maldives', - 'MX': 'Mexique', - 'MH': 'Marshall', - 'MK': 'Macedoine', - 'ML': 'Mali', - 'MT': 'Malte', - 'MM': 'Birmanie', - 'ME': 'Monténégro', - 'MN': 'Mongolie', - 'MP': 'Îles Mariannes du Nord', - 'MZ': 'Mozambique', - 'MR': 'Mauritanie', - 'MS': 'Montserrat', - 'MQ': 'Martinique', - 'MU': 'Maurice', - 'MW': 'Malawi', - 'MY': 'Malaisie', - 'YT': 'Mayotte', - 'NA': 'Namibie', - 'NC': 'Nouvelle-Calédonie', - 'NE': 'Niger', - 'NF': 'Île Norfolk', - 'NG': 'Nigeria', - 'NI': 'Nicaragua', - 'NU': 'Niue', - 'NL': 'Pays-Bas', - 'NO': 'Norvège', - 'NP': 'Nepal', - 'NR': 'Nauru', - 'NZ': 'Nouvelle-Zélande', - 'OM': 'Oman', - 'PK': 'Pakistan', - 'PA': 'Panama', - 'PN': 'Îles Pitcairn', - 'PE': 'Pérou', - 'PH': 'Philippines', - 'PW': 'Palaos', - 'PG': 'Papouasie-Nouvelle-Guinée', - 'PL': 'Pologne', - 'PR': 'Porto Rico', - 'KP': 'Corée du Nord', - 'PT': 'Portugal', - 'PY': 'Paraguay', - 'PS': 'Palestine', - 'PF': 'Polynésie française', - 'QA': 'Qatar', - 'RE': 'Réunion', - 'RO': 'Roumanie', - 'RU': 'Russie', - 'RW': 'Rwanda', - 'SA': 'Arabie saoudite', - 'SD': 'Soudan', - 'SN': 'Sénégal', - 'SG': 'Singapour', - 'GS': 'Georgie du Sud-et-les iles Sandwich du Sud', - 'SH': 'Sainte-Hélène, Ascension et Tristan da Cunha', - 'SJ': 'Svalbard et île Jan Mayen', - 'SB': 'Salomon', - 'SL': 'Sierra Leone', - 'SV': 'Salvador', - 'SM': 'Saint-Marin', - 'SO': 'Somalie', - 'PM': 'Saint-Pierre-et-Miquelon', - 'RS': 'Serbie', - 'SS': 'Soudan du Sud', - 'ST': 'Sao Tomé-et-Principe', - 'SR': 'Suriname', - 'SK': 'Slovaquie', - 'SI': 'Slovénie', - 'SE': 'Suède', - 'SZ': 'eSwatani', - 'SX': 'Saint-Martin ', - 'SC': 'Seychelles', - 'SY': 'Syrie', - 'TC': 'Îles Turques-et-Caïques', - 'TD': 'Tchad', - 'TG': 'Togo', - 'TH': 'Thaïlande', - 'TJ': 'Tadjikistan', - 'TK': 'Tokelau', - 'TM': 'Turkmenistan', - 'TL': 'Timor oriental', - 'TO': 'Tonga', - 'TT': 'Trinité-et-Tobago', - 'TN': 'Tunisie', - 'TR': 'Turquie', - 'TV': 'Tuvalu', - 'TW': 'Taiwan', - 'TZ': 'Tanzanie', - 'UG': 'Ouganda', - 'UA': 'Ukraine', - 'UY': 'Uruguay', - 'US': 'Etats-Unis', - 'UZ': 'Ouzbékistan', - 'VA': 'Saint-Siège (État de la Cité du Vatican)', - 'VC': 'Saint-Vincent-et-les-Grenadines', - 'VE': 'Venezuela', - 'VG': 'Îles Vierges britanniques', - 'VI': 'Îles Vierges des États-Unis', - 'VN': 'Viêt Nam', - 'VU': 'Vanuatu', - 'WF': 'Wallis-et-Futuna', - 'WS': 'Samoa', - 'XK': 'Kosovo', - 'YE': 'Yémen', - 'ZA': 'Afrique du Sud', - 'ZM': 'Zambie', - 'ZW': 'Zimbabwe' - } +landcode2 = lang.all[globs.CNIRlang]["LANDCODE2"] -landcode3 = { - 'ABW': 'Aruba', - 'AFG': 'Afghanistan', - 'AGO': 'Angola', - 'AIA': 'Anguilla', - 'ALB': 'Albanie', - 'AND': 'Andorre', - 'ARE': 'Emirats arabes unis', - 'ARG': 'Argentine', - 'ARM': 'Arménie', - 'ASM': 'Samoa américaines', - 'ATA': 'Antarctique', - 'ATF': 'Terres australes et antarctiques françaises', - 'ATG': 'Antigua-et-Barbuda', - 'AUS': 'Australie', - 'AUT': 'Autriche', - 'AZE': 'Azerbaidjan', - 'BDI': 'Burundi', - 'BEL': 'Belgique', - 'BEN': 'Benin', - 'BES': 'Pays-Bas caribéens', - 'BFA': 'Burkina Faso', - 'BGD': 'Bangladesh', - 'BGR': 'Bulgarie', - 'BHR': 'Bahrein', - 'BHS': 'Bahamas', - 'BIH': 'Bosnie-Herzegovine', - 'BLM': 'Saint-Barthélemy', - 'BLR': 'Bielorussie', - 'BLZ': 'Belize', - 'BMU': 'Bermudes', - 'BOL': 'Bolivie', - 'BRA': 'Brésil', - 'BRB': 'Barbade', - 'BRN': 'Brunei', - 'BTN': 'Bhoutan', - 'BWA': 'Botswana', - 'CAF': 'République Centrafricaine', - 'CAN': 'Canada', - 'CCK': 'Îles Cocos', - 'CHE': 'Suisse', - 'CHL': 'Chili', - 'CHN': 'Chine', - 'CIV': "Côte d'Ivoire", - 'CMR': 'Cameroun', - 'COD': 'Congo (République démocratique)', - 'COG': 'Congo (République)', - 'COK': 'Îles Cook', - 'COL': 'Colombie', - 'COM': 'Comores', - 'CPV': 'Cap-Vert', - 'CRI': 'Costa Rica', - 'CUB': 'Cuba', - 'CUW': 'Curaçao', - 'CXR': 'Île Christmas', - 'CYM': 'Caimans', - 'CYP': 'Chypre', - 'CZE': 'Tchéquie', - 'DEU': 'Allemagne', - 'DJI': 'Djibouti', - 'DMA': 'Dominique', - 'DNK': 'Danemark', - 'DOM': 'République dominicaine', - 'DZA': 'Algérie', - 'ECU': 'Equateur', - 'EGY': 'Egypte', - 'ERI': 'Erythrée', - 'ESH': 'Sahara occidental', - 'ESP': 'Espagne', - 'EST': 'Estonie', - 'ETH': 'Ethiopie', - 'FIN': 'Finlande', - 'FJI': 'Fidji', - 'FLK': 'Îles Malouines', - 'FRA': 'France', - 'FRO': 'Féroé', - 'FSM': 'Micronésie', - 'GAB': 'Gabon', - 'GBR': 'Royaume-Uni', - 'GEO': 'Géorgie', - 'GGY': 'Guernesey', - 'GHA': 'Ghana', - 'GIB': 'Gibraltar', - 'GIN': 'Guinée', - 'GLP': 'Guadeloupe', - 'GMB': 'Gambie', - 'GNB': 'Guinée-Bissau', - 'GNQ': 'Guinée équatoriale', - 'GRC': 'Grèce', - 'GRD': 'Grenade', - 'GRL': 'Groenland', - 'GTM': 'Guatemala', - 'GUF': 'Guyane', - 'GUM': 'Guam', - 'GUY': 'Guyana', - 'HKG': 'Hong Kong', - 'HND': 'Honduras', - 'HRV': 'Croatie', - 'HTI': 'Haïti', - 'HUN': 'Hongrie', - 'IDN': 'Indonésie', - 'IMN': 'Île de Man', - 'IND': 'Inde', - 'IOT': "Territoire britannique de l'océan Indien", - 'IRL': 'Irlande', - 'IRN': 'Irak', - 'IRQ': 'Iran', - 'ISL': 'Islande', - 'ISR': 'Israël', - 'ITA': 'Italie', - 'JAM': 'Jamaïque', - 'JEY': 'Jersey', - 'JOR': 'Jordanie', - 'JPN': 'Japon', - 'KAZ': 'Kazakhstan', - 'KEN': 'Kenya', - 'KGZ': 'Kirghizistan', - 'KHM': 'Cambodge', - 'KIR': 'Kiribati', - 'KNA': 'Saint-Christophe-et-Niévès', - 'KOR': 'Corée du Sud', - 'KWT': 'Koweït', - 'LAO': 'Laos', - 'LBN': 'Liban', - 'LBR': 'Liberia', - 'LBY': 'Libye', - 'LCA': 'Sainte-Lucie', - 'LIE': 'Liechtenstein', - 'LKA': 'Sri Lanka', - 'LSO': 'Lesotho', - 'LTU': 'Lituanie', - 'LUX': 'Luxembourg', - 'LVA': 'Lettonie', - 'MAC': 'Macao', - 'MAF': 'Sint-Maarten', - 'MAR': 'Maroc', - 'MCO': 'Monaco', - 'MDA': 'Moldavie', - 'MDG': 'Madagascar', - 'MDV': 'Maldives', - 'MEX': 'Mexique', - 'MHL': 'Marshall', - 'MKD': 'Macedoine', - 'MLI': 'Mali', - 'MLT': 'Malte', - 'MMR': 'Birmanie', - 'MNE': 'Monténégro', - 'MNG': 'Mongolie', - 'MNP': 'Îles Mariannes du Nord', - 'MOZ': 'Mozambique', - 'MRT': 'Mauritanie', - 'MSR': 'Montserrat', - 'MTQ': 'Martinique', - 'MUS': 'Maurice', - 'MWI': 'Malawi', - 'MYS': 'Malaisie', - 'MYT': 'Mayotte', - 'NAM': 'Namibie', - 'NCL': 'Nouvelle-Calédonie', - 'NER': 'Niger', - 'NFK': 'Île Norfolk', - 'NGA': 'Nigeria', - 'NIC': 'Nicaragua', - 'NIU': 'Niue', - 'NLD': 'Pays-Bas', - 'NOR': 'Norvège', - 'NPL': 'Nepal', - 'NRU': 'Nauru', - 'NZL': 'Nouvelle-Zélande', - 'OMN': 'Oman', - 'PAK': 'Pakistan', - 'PAN': 'Panama', - 'PCN': 'Îles Pitcairn', - 'PER': 'Pérou', - 'PHL': 'Philippines', - 'PLW': 'Palaos', - 'PNG': 'Papouasie-Nouvelle-Guinée', - 'POL': 'Pologne', - 'PRI': 'Porto Rico', - 'PRK': 'Corée du Nord', - 'PRT': 'Portugal', - 'PRY': 'Paraguay', - 'PSE': 'Palestine', - 'PYF': 'Polynésie française', - 'QAT': 'Qatar', - 'REU': 'Réunion', - 'ROU': 'Roumanie', - 'RUS': 'Russie', - 'RWA': 'Rwanda', - 'SAU': 'Arabie saoudite', - 'SDN': 'Soudan', - 'SEN': 'Sénégal', - 'SGP': 'Singapour', - 'SGS': 'Georgie du Sud-et-les iles Sandwich du Sud', - 'SHN': 'Sainte-Hélène, Ascension et Tristan da Cunha', - 'SJM': 'Svalbard et île Jan Mayen', - 'SLB': 'Salomon', - 'SLE': 'Sierra Leone', - 'SLV': 'Salvador', - 'SMR': 'Saint-Marin', - 'SOM': 'Somalie', - 'SPM': 'Saint-Pierre-et-Miquelon', - 'SRB': 'Serbie', - 'SSD': 'Soudan du Sud', - 'STP': 'Sao Tomé-et-Principe', - 'SUR': 'Suriname', - 'SVK': 'Slovaquie', - 'SVN': 'Slovénie', - 'SWE': 'Suède', - 'SWZ': 'eSwatani', - 'SXM': 'Saint-Martin ', - 'SYC': 'Seychelles', - 'SYR': 'Syrie', - 'TCA': 'Îles Turques-et-Caïques', - 'TCD': 'Tchad', - 'TGO': 'Togo', - 'THA': 'Thaïlande', - 'TJK': 'Tadjikistan', - 'TKL': 'Tokelau', - 'TKM': 'Turkmenistan', - 'TLS': 'Timor oriental', - 'TON': 'Tonga', - 'TTO': 'Trinité-et-Tobago', - 'TUN': 'Tunisie', - 'TUR': 'Turquie', - 'TUV': 'Tuvalu', - 'TWN': 'Taiwan', - 'TZA': 'Tanzanie', - 'UGA': 'Ouganda', - 'UKR': 'Ukraine', - 'URY': 'Uruguay', - 'USA': 'Etats-Unis', - 'UZB': 'Ouzbékistan', - 'VAT': 'Saint-Siège (État de la Cité du Vatican)', - 'VCT': 'Saint-Vincent-et-les-Grenadines', - 'VEN': 'Venezuela', - 'VGB': 'Îles Vierges britanniques', - 'VIR': 'Îles Vierges des États-Unis', - 'VNM': 'Viêt Nam', - 'VUT': 'Vanuatu', - 'WLF': 'Wallis-et-Futuna', - 'WSM': 'Samoa', - 'XKX': 'Kosovo', - 'YEM': 'Yémen', - 'ZAF': 'Afrique du Sud', - 'ZMB': 'Zambie', - 'ZWE': 'Zimbabwe', - 'NTZ': 'Zone neutre', - 'UNO': 'Fonctionnaire des Nations Unies', - 'UNA': "Fonctionnaire d'une organisation affiliée aux Nations Unies", - 'UNK': 'Représentant des Nations Unies au Kosovo', - 'XXA': 'Apatride Convention 1954', - 'XXB': 'Réfugié Convention 1954', - 'XXC': 'Réfugié autre', - 'XXX': 'Résident Légal de Nationalité Inconnue', - 'D': 'Allemagne', - 'EUE': 'Union Européenne', - 'GBD': "Citoyen Britannique d'Outre-mer (BOTC)", - 'GBN': 'British National (Overseas)', - 'GBO': 'British Overseas Citizen', - 'GBP': 'British Protected Person', - 'GBS': 'British Subject', - 'XBA': 'Banque Africaine de Développement', - 'XIM': "Banque Africaine d'Export–Import", - 'XCC': 'Caribbean Community or one of its emissaries', - 'XCO': 'Common Market for Eastern and Southern Africa', - 'XEC': 'Economic Community of West African States', - 'XPO': 'International Criminal Police Organization', - 'XOM': 'Sovereign Military Order of Malta', - 'RKS': 'Kosovo', - 'WSA': 'World Service Authority World Passport' -} +landcode3 = lang.all[globs.CNIRlang]["LANDCODE3"] ## DOCUMENTS TYPES @@ -576,7 +61,7 @@ P = [ "D": ["1", "CTRLF", "[0-9]", "C"], "E": ["1", "CTRL", "[0-9]", "4578ABCD"] }, - "Passeport" + lang.all[globs.CNIRlang]["Passeport"] ] IP = [ @@ -596,7 +81,7 @@ IP = [ "C": ["11", "FACULT", ".+"], "D": ["1", "CTRL", "[0-9]", "345679AC"] }, - "Carte-passeport" + lang.all[globs.CNIRlang]["Carte-passeport"] ] I_ = [ @@ -616,7 +101,7 @@ I_ = [ "C": ["11", "FACULT", ".+"], "D": ["1", "CTRL", "[0-9]", "345679AC"] }, - "Titre d'identité/de voyage" + lang.all[globs.CNIRlang]["Titre d'identité/de voyage"] ] AC = [ @@ -637,7 +122,7 @@ AC = [ "C": ["11", "FACULT", ".+"], "D": ["1", "CTRL", "[0-9]","345679AC"] }, - "Certificat de membre d'équipage" + lang.all[globs.CNIRlang]["Certificat de membre d'équipage"] ] VA = [ @@ -656,7 +141,7 @@ VA = [ "B": ["1", "CTRL", "[0-9]", "A"], "C": ["16", "FACULT", ".+"] }, - "Visa de type A" + lang.all[globs.CNIRlang]["Visa de type A"] ] VB = [ @@ -675,7 +160,7 @@ VB = [ "B": ["1", "CTRL", "[0-9]", "A"], "C": ["8", "FACULT", ".+"] }, - "Visa de type B" + lang.all[globs.CNIRlang]["Visa de type B"] ] TSF = [ @@ -694,7 +179,7 @@ TSF = [ "B": ["1", "CTRL", "[0-9]", "A"], "C": ["8", "FACULT", ".+"] }, - "Carte de séjour" + lang.all[globs.CNIRlang]["Carte de séjour"] ] I__ = [ @@ -714,7 +199,7 @@ I__ = [ "C": ["7", "FACULT", ".+"], "D": ["1", "CTRL", "[0-9]", "4578ABC"] }, - "Pièce d'identité/de voyage" + lang.all[globs.CNIRlang]["Pièce d'identité/de voyage"] ] IDFR = [ @@ -734,7 +219,7 @@ IDFR = [ "C": ["1", "SEX", "[A-Z]"], "D": ["1", "CTRL", "[0-9]", "123456789ABCE"] }, - "Pièce d'identité FR" + lang.all[globs.CNIRlang]["Pièce d'identité FR"] ] DL = [ @@ -748,7 +233,7 @@ DL = [ "6": ["8", "NOM", "([A-Z]|<)+"], "7": ["1", "CTRL", "[0-9]", "123456"] }, - "Permis de conduire" + lang.all[globs.CNIRlang]["Permis de conduire"] ] TYPES = [IDFR, I__, VB, VA, AC, I_, IP, P, DL, TSF] @@ -1010,6 +495,14 @@ def getDocInfos(doc, code): res["INDIC"] += value except KeyError: res["INDIC"] = value + + # Sex + elif field[0] == 'SEX': + if not value in "MF": + res[field[0]] = False + else: + res[field[0]] = value + # All other cases else: if value != "": diff --git a/src/updater.py b/src/updater.py index b41c16b..96445a7 100644 --- a/src/updater.py +++ b/src/updater.py @@ -24,7 +24,9 @@ """ from win32com.client import Dispatch -import traceback +from tkinter.messagebox import * +from tkinter import * +import pythoncom import sys import time import os @@ -34,10 +36,12 @@ import hashlib import subprocess import psutil +import critical # critical.py 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 = ' ' @@ -80,52 +84,21 @@ def exitProcess(arg): if process.pid == os.getpid(): 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 updateChannel(choice): + if choice == "Beta": + with open(globs.CNIRUrlConfig, 'w') as (configFile): + configFile.write("{}\n0\n0".format(globs.CNIRBetaURL)) + else: + with open(globs.CNIRUrlConfig, 'w') as (configFile): + configFile.write("{}\n0\n0".format(globs.CNIRDefaultURL)) def getLatestVersion(credentials): """ Returns the latest version of the software """ + + finalver, finalurl, finalchecksum = [None]*3 # Global Handlers logfile = logger.logCur @@ -155,7 +128,7 @@ def getLatestVersion(credentials): except: pass with open(globs.CNIRUrlConfig, 'w') as (configFile): - configFile.write("https://raw.githubusercontent.com/neox95/CNIRevelator/master/VERSIONS.LST\n0\n0") + configFile.write("{}\n0\n0".format(globs.CNIRDefaultURL)) # Getting the list of versions of the software logfile.printdbg('Retrieving the software versions') @@ -188,7 +161,7 @@ def getLatestVersion(credentials): else: finalurl = url finalchecksum = None - + return (finalver, finalurl, finalchecksum) @@ -200,6 +173,11 @@ def tessInstall(PATH, credentials): # Verifying that Tesseract is installed if not os.path.exists(PATH + '\\Tesseract-OCR4\\'): finalver, finalurl, finalchecksum = getLatestVersion(credentials) + + if finalurl == None: + logfile.printerr('Unable to get the Tesseract url') + return False + tesseracturl = finalurl.replace("CNIRevelator.zip", "tesseract_4.zip") # WE ASSUME THAT THE MAIN FILE IS CNIRevelator.zip AND THAT THE TESSERACT PACKAGE IS tesseract_4.zip @@ -228,7 +206,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 +239,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 +264,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 +276,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 +287,16 @@ def batch(credentials): logfile.printdbg('Extracted :' + UPATH + '\\CNIRevelator.exe') # Make a shortcut - createShortcut("CNIRevelator.lnk", UPATH + '\\CNIRevelator.exe', UPATH) + # hide main window + pythoncom.CoInitialize() + 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 +304,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 +320,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 +346,24 @@ 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 + print(sys.argv) 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())) + critical.crashCNIR() launcherWindow.printmsg('ERROR : ' + str(e)) time.sleep(3) launcherWindow.exit() @@ -410,7 +374,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 +383,7 @@ def umain(): launcherWindow.exit() return 0 except: - logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc())) + critical.crashCNIR() launcherWindow.exit() sys.exit(2) return 2 @@ -429,7 +393,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())) + critical.crashCNIR() launcherWindow.printmsg('ERROR : ' + str(e)) time.sleep(3) launcherWindow.exit() @@ -437,16 +401,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())) + critical.crashCNIR() launcherWindow.exit() sys.exit(2) return 2