diff --git a/src/test_pass.py b/src/test_pass.py
index 0c8ba26c56b1c193ec6863d3d569a0ee9cbcde24..2ffdcb995205d106b86b0785159e5ccbaece429b 100644
--- a/src/test_pass.py
+++ b/src/test_pass.py
@@ -21,12 +21,7 @@ from dateutil.parser import parse
 from itertools import combinations
 from zxcvbn import zxcvbn
 from zxcvbn.matching import add_frequency_lists
-
-
-def tr(text):
-    # TODO translation
-    return text
-
+from translations import tr
 
 def add_dictionnaries():
     dicts = {}
@@ -43,19 +38,21 @@ def add_dictionnaries():
 # Process user inputs:
 #   Generate all possibile combinations of 2 parts of dates
 def process_input(inputs):
-    dates = []
-    words = []
-    for i in inputs:
-        try:
-            date = parse(i)
-            dates += date.strftime("%d-%m-%y-%B-%Y-%A").split('-')
-        except:
-            words.append(i)
-    for n in range(2, 4):
-        for subset in combinations(dates, n):
-            words.append("".join(subset))
-    print(words)
-    return words
+    try :
+        dates = []
+        words = []
+        for i in inputs:
+            try:
+                date = parse(i)
+                dates += date.strftime("%d-%m-%y-%B-%Y-%A").split('-')
+            except:
+                words.append(i)
+        for n in range(2, 4):
+            for subset in combinations(dates, n):
+                words.append("".join(subset))
+        return words
+    except:
+        return None
 
 
 def test_pass(password, inputs):
@@ -68,31 +65,27 @@ def test_pass(password, inputs):
     lines.append("Résultats du test\n")
     lines.append("Nombre de tentatives : {}".format(results["guesses"]))
 
-    # TODO let tr handle things
-    times = results["crack_times_display"]
     lines.append("Temps requis pour craquer votre mot de passe")
-    lines.append("\t Dump bases de donnée mal protégée : \t**{}**".format(
-        tr(times["offline_fast_hashing_1e10_per_second"])))
-    lines.append("\t Dump bases de donnée, bien protégée : \t**{}**".format(
-        tr(times["offline_slow_hashing_1e4_per_second"])))
-    lines.append("\t En ligne, sans protection anti bruteforce : \t**{}**".format(
-        tr(times["online_no_throttling_10_per_second"])))
-    lines.append("\t En ligne, avec protection anti bruteforce : \t**{}**".format(
-        tr(times["online_throttling_100_per_hour"])))
+    for key, value in results["crack_times_display"].items():
+        lines.append("\t "+tr(key).capitalize()+" :\t **"+tr(value)+"**")
 
     lines.append("\n")
     lines.append("Methode de hack utilisées")
     # Print hack methods
-    print(results["sequence"])
     for seq in results["sequence"]:
         if seq["pattern"] == "bruteforce":
             lines.append("\tMot de passe trouvé par force brute")
         elif seq["pattern"] == "repeat":
             for match in seq["base_matches"]:
-                print("\tMot de passe trouvé par repetition depuis le dictionnaire {}".
-                      format(tr(match["dictionary_name"])))
+                line = "\tMot de passe trouvé par répétitions depuis"
+                try:
+                    line += "le dictionnaire '{}'".format(tr(match["dictionary_name"]))
+                except:
+                    line += "le motif '{}'".format(tr(match["token"]))
+                finally:
+                    lines.append(line)
         elif seq["pattern"] == "date":
-            lines.append("\tMot de passe trouvé par dates")
+            lines.append("\tMot de passe trouvé par essai de dates")
         elif seq["pattern"] == "sequence":
             lines.append("\tMot proche trouvé dans la séquence : '{}'".format(tr(seq["sequence_name"])))
         else:
@@ -100,12 +93,9 @@ def test_pass(password, inputs):
 
     lines.append("\n")
 
-    valeur = ["Tres faible", "Faible", "Acceptable", "Correct", "Bon"]
-    lines.append("Score Global {}/4 : {}".format(results["score"], valeur[results["score"]]))
-
     for key, values in results["feedback"].items():
         if values != [] and values != "":
-            lines.append("{} :".format(tr(key)))
+            lines.append("{} :".format(tr(key).capitalize()))
         else:
             continue
         if not isinstance(values, list):
@@ -113,4 +103,8 @@ def test_pass(password, inputs):
             values = [values]
         for val in values:
             lines.append("\t{}".format(tr(val)))
+
+    valeur = ["Très faible", "Faible", "Tolérable", "Correct", "Bon"]
+    lines.append("Score Global {}/4 : {}".format(results["score"], valeur[results["score"]]))
+
     return lines
diff --git a/src/translations.py b/src/translations.py
new file mode 100644
index 0000000000000000000000000000000000000000..1dac12b30b195228213bf280c0eb0ce0b50b25d3
--- /dev/null
+++ b/src/translations.py
@@ -0,0 +1,91 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*
+# Copyright (C) 2017 Tetras Libre <contact@Tetras-Libre.fr>
+# Author: Beniamine, David <David.Beniamine@Tetras-Libre.fr>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Translation: technical english to NOT technical french
+
+import re
+
+translations = {
+    'offline_fast_hashing_1e10_per_second': 'Essai sur base de donnée volée mal protégée',
+    'offline_slow_hashing_1e4_per_second': 'Essai sur base de donnée volée bien protégée',
+    'online_no_throttling_10_per_second': 'Essai en ligne sans protection anti brute force',
+    'online_throttling_100_per_hour': 'Essai en ligne avec protection anti brute force',
+    'passwords': 'mots de passes',
+    'surnames': 'nom de famille',
+    'user_input': "indices données par l'attaquant.e",
+    'suggestions': 'conseils',
+    'warning': 'problèmes',
+    'less than a second': "moins d'une seconde",
+    'less than a minute': "moins d'une minute",
+}
+
+substitutions = {
+    'less than': "moins de",
+    'day': 'jour',
+    'second(s*)': 'seconde\g<1>',
+    'hour(s*)': 'heure\g<1>',
+    'months*': 'mois',
+    'year(s*)': 'an\g<1>',
+    'centuries': 'des siècles',
+    'centuries': 'des siècles',
+    "Predictable substitutions like (.*) instead of (.*) don't help very much":
+        "Les substitutions prévisibles tels que \g<1> au lieu de \g<2> n'aident pas beaucoup",
+    'Uncommon words are better': 'Préférer des mots rares',
+    'Add another word or two': 'Ajouter un mot ou deux',
+    'This is similar to a commonly used password': 'Ce mot de passe ressemble à un mot de passe très utilisé',
+    'lower': 'minuscules',
+    'upper': 'majuscules',
+    'digits': 'chiffres',
+    'unicode': 'caractères unicodes',
+    'Use a few words, avoid common phrases': 'Utiliser plusieurs mots, évitez les phrases classiques',
+    'No need for symbols, digits, or uppercase letters': 'pas besoin de symboles, nombres ou majuscules',
+    'are easy to guess': 'sont faciles à deviner',
+    'Straight rows of keys': 'Les suites directes de lettres sur le clavier',
+    'Short keyboard patterns': 'Des petits déplacement sur le clavier',
+    'Use a longer keyboard pattern with more turn': 'Utiliser un plus long schéma sur le clavier avec plus de virages',
+    'Repeats like': 'Les répétitions telles que',
+    'are only slightly harder to guess than': 'sont a peine plus difficile à deviner que',
+    'Sequences like': 'Les sequences telles que',
+    '<or>': 'ou',
+    'Avoid repeated words and characters': 'Éviter les répétitions de mots ou caractères',
+    'Avoid': 'Éviter',
+    'recent years': 'les années récentes',
+    'years that are associated with you': 'les années qui ont quelque chose à voir avec vous',
+    'Dates are often easy to guess': 'Les dates sont souvent faciles à deviner',
+    'dates': 'les dates',
+    'This is a top-(.*) common password': 'Ce mot de passe est dans le top \g<1> des plus utilisés',
+    'This is a very common passowrd': 'Ce mot de passe est très utilisé',
+    'A word by itself is easy to guess': 'Un mot seul est facile à deviner',
+    'Names and surnames by themselves': 'Les noms et noms de familles seuls',
+    'Common names and surnames': 'Les noms et noms de familles courants',
+    "Capitalization doesn't help very much": "Mettre en majuscule n'aide pas tant que ça",
+    'All-uppercase is almost as easy to guess as all-lowercase':
+        'Les mots en majuscules sont aussi simple à deviner que ceux en minuscules',
+    "Reversed words aren't much harder to guess": 'Les mots inversés ne sont pas beaucoup plus dur à deviner',
+
+}
+
+
+def tr(text):
+    try:
+        return translations[text]
+    except:
+        # Todo use regex
+        for pattern, sub in substitutions.items():
+            text = re.sub(pattern, sub, text)
+        return text