diff --git a/package.json b/package.json
index 4659066354f7753cbdd92324ea8bb72e252df356..2d99d91b9935aea8fbd53d214624c794c47622d8 100644
--- a/package.json
+++ b/package.json
@@ -11,8 +11,8 @@
     "ng": "cd . && \"node_modules/.bin/ng\"",
     "postinstall": "./node_modules/.bin/webdriver-manager update --gecko=false --versions.chrome=83.0.4103.39",
     "lint": "npm run ng -- lint",
-    "e2e": "npm run preprocess && npm run ng -- e2e --suite=regular --webdriver-update=false",
-    "e2equick": "npm run ng -- e2e --dev-server-target= --suite=regular --webdriver-update=false",
+    "e2e": "npm run preprocess && node scripts/check-translations.js && npm run ng -- e2e --suite=regular --webdriver-update=false",
+    "e2equick": "node scripts/check-translations.js && npm run ng -- e2e --dev-server-target= --suite=regular --webdriver-update=false",
     "monkeytest": "npm run ng -- e2e --dev-server-target= --suite=monkeyTest --webdriver-update=false",
     "mkdocs": "node scripts/python3.js -m mkdocs build -f mkdocs-fr.yml && node scripts/python3.js -m mkdocs build -f mkdocs-en.yml && node scripts/mkdocs-postprocess.js",
     "mkdocs2pdf": "node scripts/python3.js mkdocs2pdf.py",
diff --git a/scripts/check-translations.js b/scripts/check-translations.js
index 8beb57298f50ac1f30cdf6457f35778a309d6f6d..4143d689e4546a86d78ec4fdd665c8e9e915eb91 100644
--- a/scripts/check-translations.js
+++ b/scripts/check-translations.js
@@ -1,7 +1,24 @@
 'use strict';
 
+/**
+ * 1) Reads Message enum in jalhyd, and for every message code in it, checks
+ * that there is a translation in each nghyd's locale/*.json file (ie. for
+ * every language)
+ * 
+ * 2) For every nghyd calculator, checks that the translated keys are the same
+ * in all language files
+ */
+
 const fs = require('fs');
 
+/* IMPORTANT: during step 2, will look for those languages codes only */
+const expectedLanguages = [ "fr", "en" ];
+
+// total errors
+let nbErr = 0;
+
+// ---- 1. JaLHyd messages ----
+
 // read and transform JaLHyd message file
 const jalhydMessagesPath = "../jalhyd/src/util/message.ts";
 let jm = fs.readFileSync(jalhydMessagesPath, "utf-8");
@@ -17,10 +34,12 @@ jm = jm.replace(/\/\/.+/g, "");
 jm = jm.replace(/[ \t]+/g, "");
 // remove line breaks
 jm = jm.replace(/\n/g, "");
+
 // split on ";"
 const messages = jm.split(",");
 
-// console.log(messages);
+// remove import on 1st line (wtf) @clodo
+messages[0] = messages[0].substring(24);
 
 // read every language file
 const localePath = "src/locale";
@@ -30,15 +49,76 @@ for (let i = 0; i < localeDir.length; i++) {
     const res = localeFile.match(/^messages\.([a-z]{2})\.json$/);
     if (res) {
         const lang = res[1];
-        console.log("Loading translations for language [" + lang + "]");
+        console.log("Loading global translations for language [" + lang + "]");
         const langFilePath = localePath + '/' + localeFile;
-        let translations = Object.keys(JSON.parse(fs.readFileSync(langFilePath, "utf-8")));
+        const translations = Object.keys(JSON.parse(fs.readFileSync(langFilePath, "utf-8")));
         // console.log(translations);
         // check against JaLHyd messages list
         for (const mess of messages) {
             if (! translations.includes(mess)) {
                 console.log("  missing message in [" + lang + "] translation: " + mess);
+                nbErr++;
             }
         }
     }
 }
+
+// ---- 2. calculators localisation ----
+
+// find every calculator folder
+const calculatorsPath = "src/app/calculators";
+const calculatorsDir = fs.readdirSync(calculatorsPath);
+console.log("Checking all calculators translations for languages [" + expectedLanguages.join(", ") + "]");
+for (let i = 0; i < calculatorsDir.length; i++) {
+    const calcPath = calculatorsPath + "/" + calculatorsDir[i];
+    const stats = {};
+    // console.log(" checking calculator [" + calculatorsDir[i] + "]");
+    // find all language files for this calculator, and store translation keys
+    for (let j = 0; j < expectedLanguages.length; j++) {
+        const exLang = expectedLanguages[j];
+        const langFilePath = calcPath + "/" + exLang + ".json";
+        if (fs.existsSync(langFilePath)) {
+            const translations = Object.keys(JSON.parse(fs.readFileSync(langFilePath, "utf-8")));
+            // console.log(translations);
+            stats[exLang] = translations;
+        } else {
+            console.log(" missing language file [" + exLang + ".json] for calculator [" + calculatorsDir[i] + "]");
+            nbErr++;
+        }
+    }
+    // console.log(stats);
+    // compare number of translations per file
+    let sameNumber = true;
+    // compare keys names (order-dependent) per file
+    let sameKeys = true;
+    let prevKeys = null;
+    const sKeys = Object.keys(stats);
+    for (let k = 0; k < sKeys.length; k++) {
+        const key = sKeys[k];
+        if (k > 0) {
+            sameNumber = sameNumber && (stats[key].length === prevKeys.length);
+            sameKeys = sameKeys && (JSON.stringify(stats[key]) === JSON.stringify(prevKeys)); // compare arrays
+        }
+        prevKeys = stats[key];
+    }
+    // difference found ?
+    if (! sameNumber) {
+        console.log(" [" + calculatorsDir[i] + "]: different number of keys found", sKeys.map((s) => {
+            return s + ": " + stats[s].length;
+        }));
+        nbErr++;
+    } else if (! sameKeys) {
+        console.log(" [" + calculatorsDir[i] + "]: different keys found", stats);
+        nbErr++;
+    }
+}
+
+
+// ---- 3. JaLHyd messages ----
+
+if (nbErr === 0) {
+    console.log("Everything OK !");
+    process.exit(0);
+} else {
+    process.exit(1);
+}
diff --git a/src/app/calculators/bief/en.json b/src/app/calculators/bief/en.json
index 30465b07a001799b439f37cbd77f79b5c55a469c..83ef6c03f737582786d59d38359f40974a6e617a 100644
--- a/src/app/calculators/bief/en.json
+++ b/src/app/calculators/bief/en.json
@@ -26,8 +26,8 @@
     "fs_condlim": "Boundary conditions",
     "Q": "Upstream flow",
     "S": "Wet surface",
-    "fs_param_calc": "Calculation parameters",
     "Dx": "Discretisation step",
+    "fs_param_calc": "Calculation parameters",
     "Z1": "Upstream water elevation",
     "Z2": "Downstream water elevation",
     "ZF1": "Upstream bottom elevation",
diff --git a/src/app/calculators/cloisons/en.json b/src/app/calculators/cloisons/en.json
index 22a43f9ac81c48230975b81008a4f426f8b607bc..af443e0f84fa4abc8864354ad601a33c380e2747 100644
--- a/src/app/calculators/cloisons/en.json
+++ b/src/app/calculators/cloisons/en.json
@@ -2,9 +2,6 @@
     "Q": "Total discharge",
     "P": "Sill",
     "W": "Gate opening",
-    "ZR": "Upstream bed elevation",
-    "PB": "Pool mean depth",
-    "h1": "Head",
 
 	"UNIT_Q": "m³/s",
     "UNIT_YMOY": "m",
diff --git a/src/app/calculators/courberemous/en.json b/src/app/calculators/courberemous/en.json
index f965d3e9f8bb00e3af5dcfccf7a3a94404f632f6..c238adfb5a991db7374b0e71fceb2536c7484eaa 100644
--- a/src/app/calculators/courberemous/en.json
+++ b/src/app/calculators/courberemous/en.json
@@ -53,7 +53,7 @@
     "TARGET_Hsc": "Critical head (m)",
     "TARGET_B": "Surface width (m)",
     "TARGET_P": "Wetted perimeter (m)",
-    "TARGET_S": "Wetted area (m2)",
+    "TARGET_S": "Wet surface (m2)",
     "TARGET_R": "Hydraulic radius (m)",
     "TARGET_V": "Average speed (m/s)",
     "TARGET_Fr": "Froude number",
diff --git a/src/app/calculators/jet/en.json b/src/app/calculators/jet/en.json
index c8342e3234a4c8cc17d99573b2d28cf8fbe24b88..32cc2afed438f0b92db9d7ca8f9ee3e5f3507068 100644
--- a/src/app/calculators/jet/en.json
+++ b/src/app/calculators/jet/en.json
@@ -9,7 +9,7 @@
     "ZF": "Bottom elevation",
     "H": "Fall height",
     "Y": "Depth",
-    "YH": "Depth/height ration",
+    "YH": "Depth/height ratio",
     "t": "Flight time",
     "Vx": "Horizontal speed at impact",
     "Vz": "Vertical speed at impact",
diff --git a/src/app/calculators/lechaptcalmon/en.json b/src/app/calculators/lechaptcalmon/en.json
index 0e0b0798c73c0110466290d20c5656645b20d698..729994b0eefa9009092b821d43e3410b05358419 100644
--- a/src/app/calculators/lechaptcalmon/en.json
+++ b/src/app/calculators/lechaptcalmon/en.json
@@ -14,7 +14,6 @@
     "M": "M",
     "N": "N",
     "fs_hydraulique": "Hydraulic features",
-    "Q": "Flow",
     "D": "Pipe diameter",
     "J": "Total head loss",
     "Ks": "Singular head loss coefficient",
@@ -22,5 +21,8 @@
     "fs_param_calc": "Calculation parameters",
     "Jl": "Linear head loss",
     "Kl": "Linear head loss coefficient",
-    "fD": "Darcy friction factor"
+    "fD": "Darcy friction factor",
+
+    "UNIT_JL": "m",
+    "UNIT_V": "m/s"
 }
\ No newline at end of file
diff --git a/src/app/calculators/lechaptcalmon/fr.json b/src/app/calculators/lechaptcalmon/fr.json
index 0ce375bc6bfb74389554e1b65d75ed100e5daa0a..89884cabd4634f566ed4d86d2a419de79000447f 100644
--- a/src/app/calculators/lechaptcalmon/fr.json
+++ b/src/app/calculators/lechaptcalmon/fr.json
@@ -20,8 +20,9 @@
     "Lg": "Longueur du tuyau",
     "fs_param_calc": "Paramètres de calcul",
     "Jl": "Perte de charge linéaire",
-    "UNIT_JL": "m",
-    "UNIT_V": "m/s",
     "Kl": "Coefficient de perte de charge linéaire",
-    "fD": "Coefficient de perte de charge de Darcy"
+    "fD": "Coefficient de perte de charge de Darcy",
+
+    "UNIT_JL": "m",
+    "UNIT_V": "m/s"
 }
\ No newline at end of file
diff --git a/src/app/calculators/pabpuissance/en.json b/src/app/calculators/pabpuissance/en.json
index 582ca3f4574a5bd17f16a445ef6cec2836294260..5872528a56724df3749e24cf9ec1727c0b6b8bdd 100644
--- a/src/app/calculators/pabpuissance/en.json
+++ b/src/app/calculators/pabpuissance/en.json
@@ -1,7 +1,6 @@
 {
     "fs_puissance": "Basin dimensions",
     "DH": "Drop",
-    "Q": "Discharge",
     "V": "Volume",
     "PV": "Dissipated power"
 }
\ No newline at end of file
diff --git a/src/app/calculators/par/en.json b/src/app/calculators/par/en.json
index fc7eddd2d9cb266adb86fd8381b7d51e3e416c4a..f1d88aa176d3fee207ac7bba0b07b84095c489ac 100644
--- a/src/app/calculators/par/en.json
+++ b/src/app/calculators/par/en.json
@@ -1,10 +1,6 @@
 {
     "fs_param_hydro": "Hydraulic parameters",
 
-    "Q": "Flow",
-    "Z1": "Upstream water elevation",
-    "Z2": "Downstream water elevation",
-
     "fs_geometry": "Pass geometry",
 
     "ha": "Upstream head",
diff --git a/src/app/calculators/parsimulation/en.json b/src/app/calculators/parsimulation/en.json
index a5b752e2162fc757f4d38fbc1b111fb28ea86ffa..36c46b4b1706938004c1e6724b95665ca8c78524 100644
--- a/src/app/calculators/parsimulation/en.json
+++ b/src/app/calculators/parsimulation/en.json
@@ -1,10 +1,6 @@
 {
     "fs_param_hydro": "Hydraulic parameters",
 
-    "Q": "Flow",
-    "Z1": "Upstream water elevation",
-    "Z2": "Downstream water elevation",
-
     "fs_geometry": "Pass geometry",
 
     "ZD1": "Upstream spilling elevation",
diff --git a/src/app/calculators/sectionparametree/en.json b/src/app/calculators/sectionparametree/en.json
index 943320f64a4b42fcb06d8da12e7f3886dc790295..92a0479a837ab8d6a34e523b10719826aee6a5cc 100644
--- a/src/app/calculators/sectionparametree/en.json
+++ b/src/app/calculators/sectionparametree/en.json
@@ -17,7 +17,6 @@
     "If": "Bottom slope",
     "YB": "Embankment elevation",
     "fs_hydraulique": "Hydraulic features",
-    "Q": "Flow",
     "Y": "Draft",
     "fs_param_calc": "Calculation parameters",
     "Hs": "Specific head",
diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index dd4e31e8a8416ea6234b73a3f66ebe422123bb78..b662a5000d25250ee124089a9a93d715453b9ad5 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -433,8 +433,8 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe
                     this.setForm(this.formulaireService.getFormulaireFromId(uid));
                     this.resultsComponent.formulaire = this._formulaire;
                     this._calculatorNameComponent.model = this._formulaire;
-                    // reload localisation in all cases
-                    this.formulaireService.loadUpdateFormulaireLocalisation(this._formulaire);
+                    // reload localisation in all cases (it does not eat bread)
+                    this.formulaireService.updateFormulaireLocalisation(this._formulaire);
                     // call Form init hook
                     this._formulaire.onCalculatorInit();
                     break;
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index 140741bebf22d2d630cff6942ff6947b4ba42524..e0c346cf8ad5a72a4a242cb85cc4a5cf8bd5b0e9 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -52,12 +52,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     /** fichier de configuration */
     private _jsonConfig: {};
 
-    /** clé-valeurs du fichier de localisation spécifique à ce module */
-    private _specificLocalisation: StringMap;
-
-    /** ISO 639-1 language code of the current language (to avoid unnecessary localisation reload) */
-    private _currentLanguage: string;
-
     /** copy of options.resultsHelp read by FormDefinition.parseOptions() */
     public helpLinks: { [key: string]: string };
 
@@ -79,14 +73,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         return this._calculateDisabled;
     }
 
-    public get specificLocalisation() {
-        return this._specificLocalisation;
-    }
-
-    public get currentLanguage() {
-        return this._currentLanguage;
-    }
-
     public get calculatorType(): CalculatorType {
         const props = this._currentNub === undefined ? this.defaultProperties : (this._currentNub.properties as Props).props;
         return props["calcType"];
@@ -424,11 +410,9 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         }
     }
 
-    public updateLocalisation(localisation: StringMap, lang: string) {
-        this._specificLocalisation = localisation;
-        this._currentLanguage = lang;
+    public updateLocalisation(lang: string) {
         for (const fe of this.topFormElements) {
-            fe.updateLocalisation(localisation);
+            fe.updateLocalisation();
         }
     }
 
diff --git a/src/app/formulaire/elements/fieldset-container.ts b/src/app/formulaire/elements/fieldset-container.ts
index 1c31212daed733bd6a8a84e360f6b4a9ed09b5c0..96f719fcf0dd192ee0f7af1bf613bb9b69309b48 100644
--- a/src/app/formulaire/elements/fieldset-container.ts
+++ b/src/app/formulaire/elements/fieldset-container.ts
@@ -1,15 +1,12 @@
 import { FormulaireElement } from "./formulaire-element";
 import { FieldSet } from "./fieldset";
 import { FieldsetTemplate } from "./fieldset-template";
-import { StringMap } from "../../stringmap";
 import { FormulaireNode } from "./formulaire-node";
 import { Nub } from "jalhyd";
 
 export class FieldsetContainer extends FormulaireElement {
     private _templates: FieldsetTemplate[];
 
-    private _localisation: StringMap;
-
     public title: string;
 
     constructor(parent: FormulaireNode) {
@@ -109,11 +106,4 @@ export class FieldsetContainer extends FormulaireElement {
             }
         }
     }
-
-    public updateLocalisation(loc: StringMap = this._localisation) {
-        this._localisation = loc;
-        if (loc !== undefined) {
-            super.updateLocalisation(loc);
-        }
-    }
 }
diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts
index f9063cb45285821b85b4a7fedcd8eb35095560b1..dce1e17d48ec85a85578f333ccbf908aaca69413 100644
--- a/src/app/formulaire/elements/fieldset.ts
+++ b/src/app/formulaire/elements/fieldset.ts
@@ -11,7 +11,6 @@ import { FormulaireElement } from "./formulaire-element";
 import { Field } from "./field";
 import { SelectField } from "./select-field";
 import { NgParameter, ParamRadioConfig } from "./ngparam";
-import { StringMap } from "../../stringmap";
 import { FieldsetContainer } from "./fieldset-container";
 import { SelectFieldCustom } from "./select-field-custom";
 import { FormulaireFixedVar } from "../definition/form-fixedvar";
@@ -22,9 +21,6 @@ export class FieldSet extends FormulaireElement implements Observer {
     /** Nub associé */
     private _nub: Nub;
 
-    /** dictionnaire de traduction */
-    private _localisation: StringMap;
-
     /** fichier de configuration */
     private _jsonConfig: {};
 
@@ -203,18 +199,6 @@ export class FieldSet extends FormulaireElement implements Observer {
         this.clearKids();
     }
 
-    public updateLocalisation(loc?: StringMap) {
-        if (! loc) {
-            loc = this._localisation;
-        } else {
-            this._localisation = loc;
-        }
-
-        if (loc) {
-            super.updateLocalisation(loc);
-        }
-    }
-
     /**
      * Reloads the model values and properties, and reloads localisation strings
      */
diff --git a/src/app/formulaire/elements/formulaire-element.ts b/src/app/formulaire/elements/formulaire-element.ts
index 95c14c76d51a5ad2004d2468b5557b649ae66407..579b62648b34a662d8edba307d86920a98ff32d3 100644
--- a/src/app/formulaire/elements/formulaire-element.ts
+++ b/src/app/formulaire/elements/formulaire-element.ts
@@ -1,8 +1,7 @@
 import { FormulaireNode } from "./formulaire-node";
-import { StringMap } from "../../stringmap";
-import { I18nService } from "../../services/internationalisation.service";
 import { ServiceFactory } from "../../services/service-factory";
 import { FormulaireDefinition } from "../definition/form-definition";
+import { FormulaireService } from "../../services/formulaire.service";
 
 /**
  * élément (enfant) du formulaire : fieldset, input, container, ...
@@ -18,7 +17,7 @@ export abstract class FormulaireElement extends FormulaireNode {
      */
     protected _label: string;
 
-    private intlService: I18nService;
+    private formulaireService: FormulaireService;
 
     public static removePrefix(s: string, prefix: string): string {
         if (s.startsWith(prefix)) {
@@ -30,7 +29,7 @@ export abstract class FormulaireElement extends FormulaireNode {
     constructor(parent: FormulaireNode) {
         super(parent);
         this._isDisplayed = true;
-        this.intlService = ServiceFactory.i18nService;
+        this.formulaireService = ServiceFactory.formulaireService;
     }
 
     get isDisplayed(): boolean {
@@ -71,13 +70,10 @@ export abstract class FormulaireElement extends FormulaireNode {
      * @param loc calculator-specific localised messages map
      * @param key Element label key
      */
-    public updateLocalisation(loc: StringMap, key?: string) {
-        if (!key) {
-            key = this._confId;
-        }
-        this._label = this.intlService.localizeText(key, loc);
+    public updateLocalisation() {
+        this._label = this.formulaireService.localizeText(this._confId, this.parentForm.currentNub.calcType);
         for (const f of this.getKids()) {
-            f.updateLocalisation(loc);
+            f.updateLocalisation();
         }
     }
 
diff --git a/src/app/formulaire/elements/select-field.ts b/src/app/formulaire/elements/select-field.ts
index 9be231395892bab31c6003d5ac62774a64acedbb..0884f25641cb3a37472be53baa6f0d928a7453fe 100644
--- a/src/app/formulaire/elements/select-field.ts
+++ b/src/app/formulaire/elements/select-field.ts
@@ -10,7 +10,6 @@ import {
 
 import { Field } from "./field";
 import { SelectEntry } from "./select-entry";
-import { StringMap } from "../../stringmap";
 import { FormulaireNode } from "./formulaire-node";
 import { FormulaireDefinition } from "../definition/form-definition";
 import { ServiceFactory } from "../../services/service-factory";
@@ -110,13 +109,32 @@ export class SelectField extends Field {
         }, this);
     }
 
-    public updateLocalisation(loc: StringMap) {
-        super.updateLocalisation(loc);
+    public updateLocalisation() {
+        super.updateLocalisation();
         for (const e of this._entries) {
-            // some Select fields already have a translated label at this time; translate others
-            if (e.label === undefined) {
+            if (this.source === "solveur_targetted_result") {
+                // @WARNING clodo hack for Solveur
+                // 1. calculated param
+                const nub: Nub = (this.parentForm as FormulaireDefinition).currentNub;
+                const ntc = (nub as Solveur).nubToCalculate;
+                if (e.value !== undefined && ntc !== undefined) {
+                    if (e.value === "" && ntc.calculatedParam !== undefined) {
+                        const varName = ServiceFactory.formulaireService.expandVariableName(ntc.calcType, ntc.calculatedParam.symbol);
+                        e.label = `${varName} (${ntc.calculatedParam.symbol})`;
+                    } else {
+                        // 2. extra results
+                        const varName = ServiceFactory.formulaireService.expandVariableName(ntc.calcType, e.value);
+                        e.label = `${varName} (${e.value})`;
+                    }
+                }
+            } else {
+                // general case
                 const aId = e.id.split("_");
-                e.label = ServiceFactory.i18nService.localizeText(`${aId[1].toUpperCase()}_${aId[2]}`, loc);
+                const trad = ServiceFactory.formulaireService.localizeText(
+                    `${aId[1].toUpperCase()}_${aId[2]}`,
+                    this.parentForm.currentNub.calcType
+                );
+                e.label = trad;
             }
         }
     }
@@ -155,25 +173,16 @@ export class SelectField extends Field {
 
             // driven by string[], not enum
             case "solveur_targetted_result":
+                // @WARNING for localisation, @see hack in this.updateLocalisation()
                 // 1. calculated param
                 const ntc = (nub as Solveur).nubToCalculate;
                 if (ntc !== undefined && ntc.calculatedParam !== undefined) { // some nubs have no calculatedParam, for ex. SectionParam
-                    const varName = ServiceFactory.formulaireService.expandVariableName(ntc.calcType, ntc.calculatedParam.symbol);
-                    this.addEntry(new SelectEntry(
-                        this._entriesBaseId + "none",
-                        "",
-                        `${varName} (${ntc.calculatedParam.symbol})`
-                    ));
+                    this.addEntry(new SelectEntry(this._entriesBaseId + "none", ""));
                 }
                 // 2. extra results
                 if (ntc !== undefined && ntc.resultsFamilies !== undefined) {
                     for (const er of Object.keys(ntc.resultsFamilies)) {
-                        const varName = ServiceFactory.formulaireService.expandVariableName(ntc.calcType, er);
-                        const e: SelectEntry = new SelectEntry(
-                            this._entriesBaseId + er,
-                            er,
-                            `${varName} (${er})`
-                        );
+                        const e: SelectEntry = new SelectEntry(this._entriesBaseId + er, er);
                         this.addEntry(e);
                     }
                 }
diff --git a/src/app/services/formulaire.service.ts b/src/app/services/formulaire.service.ts
index d4cdb6ef29af0b04ac60d3991cf1a3ea151bde0e..462b312c4440326badecbb5202120e8c6a28d845 100644
--- a/src/app/services/formulaire.service.ts
+++ b/src/app/services/formulaire.service.ts
@@ -26,7 +26,6 @@ import { FormulaireDefinition } from "../formulaire/definition/form-definition";
 import { FormulaireElement } from "../formulaire/elements/formulaire-element";
 import { InputField } from "../formulaire/elements/input-field";
 import { SelectField } from "../formulaire/elements/select-field";
-import { StringMap } from "../stringmap";
 import { FormulaireSectionParametree } from "../formulaire/definition/form-section-parametree";
 import { FormulaireCourbeRemous } from "../formulaire/definition/form-courbe-remous";
 import { FormulaireParallelStructure } from "../formulaire/definition/form-parallel-structures";
@@ -52,8 +51,10 @@ export class FormulaireService extends Observable {
 
     private _currentFormId: string = null;
 
-    /** to avoid loading language files multiple times */
-    private _languageCache = {};
+    public static getConfigPathPrefix(ct: CalculatorType): string {
+        const ctName = CalculatorType[ct].toLowerCase();
+        return "app/calculators/" + ctName + "/";
+    }
 
     constructor(
         private i18nService: I18nService,
@@ -66,84 +67,16 @@ export class FormulaireService extends Observable {
         this._formulaires = [];
     }
 
-    private get _intlService(): I18nService {
-        return this.i18nService;
-    }
-
-    private get _httpService(): HttpService {
-        return this.httpService;
-    }
-
     public get formulaires(): FormulaireDefinition[] {
         return this._formulaires;
     }
 
-    public get languageCache() {
-        return this._languageCache;
-    }
-
-    /**
-     * Loads the localisation file dedicated to calculator type ct; tries the current
-     * language then the fallback language; uses cache if available
-     */
-    public loadLocalisation(calc: CalculatorType): Promise<any> {
-        const lang = this._intlService.currentLanguage;
-        return this.loadLocalisationForLang(calc, lang).then((localisation) => {
-            return localisation as StringMap;
-        }).catch((e) => {
-            console.error(e);
-            // try default lang (the one in the config file) ?
-            const fallbackLang = this.appSetupService.fallbackLanguage;
-            if (lang !== fallbackLang) {
-                console.error(`trying fallback language: ${fallbackLang}`);
-                return this.loadLocalisationForLang(calc, fallbackLang);
-            }
-        });
-    }
-
-    /**
-     * Loads the localisation file dedicated to calculator type ct for language lang;
-     * keeps it in cache for subsequent calls ()
-     */
-    private loadLocalisationForLang(calc: CalculatorType, lang: string): Promise<any> {
-        const ct = String(calc);
-        // already in cache ?
-        if (Object.keys(this._languageCache).includes(ct) && Object.keys(this._languageCache[calc]).includes(lang)) {
-            return new Promise((resolve) => {
-                resolve(this._languageCache[ct][lang]);
-            });
-        } else {
-            const f: string = this.getConfigPathPrefix(calc) + lang + ".json";
-            return this._httpService.httpGetRequestPromise(f).then((localisation) => {
-                this._languageCache[ct] = this._languageCache[ct] || {};
-                this._languageCache[ct][lang] = localisation;
-                return localisation as StringMap;
-            }).catch((e) => {
-                throw new Error(`LOCALISATION_FILE_NOT_FOUND "${f}"`);
-            });
-        }
-    }
-
-    /**
-     * Loads localisation file corresponding to current language then updates all form strings,
-     * only if form language was not already set to current language
-     */
-    public loadUpdateFormulaireLocalisation(f: FormulaireDefinition): Promise<FormulaireDefinition> {
-        const requiredLang = this._intlService.currentLanguage;
-        if (requiredLang !== f.currentLanguage) {
-            return this.loadLocalisation(f.calculatorType).then(localisation => {
-                f.updateLocalisation(localisation, requiredLang);
-                return f;
-            });
-        }
-    }
-
     /**
      * Retourne le titre complet du type de module de calcul, dans la langue en cours
      */
     public getLocalisedTitleFromCalculatorType(type: CalculatorType) {
         const sCalculator: string = CalculatorType[type].toUpperCase();
-        return this._intlService.localizeText(`INFO_${sCalculator}_TITRE`);
+        return this.intlService.localizeText(`INFO_${sCalculator}_TITRE`);
     }
 
     /**
@@ -151,7 +84,7 @@ export class FormulaireService extends Observable {
      */
     public getLocalisedDescriptionFromCalculatorType(type: CalculatorType) {
         const sCalculator: string = CalculatorType[type].toUpperCase();
-        return this._intlService.localizeText(`INFO_${sCalculator}_DESCRIPTION`);
+        return this.intlService.localizeText(`INFO_${sCalculator}_DESCRIPTION`);
     }
 
     /**
@@ -163,7 +96,44 @@ export class FormulaireService extends Observable {
             type = CalculatorType[type];
         }
         const sCalculator: string = type.toUpperCase();
-        return this._intlService.localizeText(`INFO_${sCalculator}_TITRE_COURT`);
+        return this.intlService.localizeText(`INFO_${sCalculator}_TITRE_COURT`);
+    }
+
+    /**
+     * Forces update of all form strings in given Formulaire, with current language
+     */
+    public updateFormulaireLocalisation(f: FormulaireDefinition) {
+        const requiredLang = this.intlService.currentLanguage;
+        f.updateLocalisation(requiredLang);
+    }
+
+
+    /**
+     * Tente de trouver une traduction pour textKey dans les fichiers de langues
+     * spécifiques du module de calcul en cours, dans la langue en cours, puis
+     * dans la langue par défaut; si aucune traduction n'est trouvée, demande au
+     * service i18n de rechercher dans les fichiers de langues globaux
+     * @param textKey la clé du texte à traduire
+     */
+    public localizeText(textKey: string, ct: CalculatorType): string {
+        const calcType = /* this.currentForm?.currentNub?.calcType || */ ct;
+        if (calcType !== undefined) {
+            // throw new Error("FormulaireService.localizeText(): cannot find CalculatorType for current form's Nub");
+            let langCache = this.i18nService.languageCache;
+            if (langCache && langCache[calcType]) {
+                langCache = langCache[calcType]; // …for target Nub type
+            }
+            // try current language
+            if (
+                langCache
+                && langCache[this.intlService.currentLanguage]
+                && langCache[this.intlService.currentLanguage][textKey] !== undefined
+            ) {
+                return langCache[this.intlService.currentLanguage][textKey];
+            }
+        }
+        // fallback to global (not calculator type specific) translation system
+        return this.i18nService.localizeText(textKey);
     }
 
     /**
@@ -174,7 +144,7 @@ export class FormulaireService extends Observable {
     public expandVariableName(calcType: CalculatorType, symbol: string): string {
         let s = "";
         // language cache…
-        let langCache = this.languageCache;
+        let langCache = this.i18nService.languageCache;
         if (langCache && langCache[calcType]) {
             langCache = langCache[calcType]; // …for target Nub type
         }
@@ -182,7 +152,7 @@ export class FormulaireService extends Observable {
             langCache = langCache[this.intlService.currentLanguage]; // … for current language
         }
         if (langCache && langCache[symbol] !== undefined) {
-            s = this.intlService.localizeText(symbol, langCache);
+            s = this.localizeText(symbol, calcType);
         } else {
             // is symbol of the form ouvrages[i]… ?
             const re = /([A-Z,a-z]+)\[(\d+)\]\.(.+)/;
@@ -207,7 +177,7 @@ export class FormulaireService extends Observable {
      */
     public expandVariableNameAndUnit(calcType: CalculatorType, symbol: string, forceUnit?: string): string {
         let s = this.expandVariableName(calcType, symbol);
-        let langCache = this.languageCache; // language cache…
+        let langCache = this.i18nService.languageCache; // language cache…
         if (langCache && langCache[calcType]) {
             langCache = langCache[calcType]; // …for target Nub type
         }
@@ -236,7 +206,7 @@ export class FormulaireService extends Observable {
             } else {
                 const unitKey = "UNIT_" + symbolBase;
                 if (langCache && langCache[unitKey] !== undefined) {
-                    unit = this.intlService.localizeText(unitKey, langCache);
+                    unit = this.localizeText(unitKey, calcType);
                 }
             }
         }
@@ -282,8 +252,8 @@ export class FormulaireService extends Observable {
     }
 
     public loadConfig(ct: CalculatorType): Promise<any> {
-        const f: string = this.getConfigPathPrefix(ct) + "config.json";
-        return this._httpService.httpGetRequestPromise(f);
+        const f: string = FormulaireService.getConfigPathPrefix(ct) + "config.json";
+        return this.httpService.httpGetRequestPromise(f);
     }
 
     private newFormulaire(ct: CalculatorType): FormulaireDefinition {
@@ -362,8 +332,7 @@ export class FormulaireService extends Observable {
         const f: FormulaireDefinition = this.newFormulaire(ct);
         this._formulaires.push(f);
         // Charge la configuration dépendamment du type
-        const prom: Promise<any> = this.loadConfig(ct);
-        return prom.then(s => {
+        return this.loadConfig(ct).then(s => {
             f.preparseConfig(s);
 
             // Associe le Nub fourni (chargement de session / duplication de module), sinon en crée un nouveau
@@ -530,11 +499,6 @@ export class FormulaireService extends Observable {
         }
     }
 
-    public getConfigPathPrefix(ct: CalculatorType): string {
-        const ctName = CalculatorType[ct].toLowerCase();
-        return "app/calculators/" + ctName + "/";
-    }
-
     /**
      * Supprime le formulaire ciblé, et demande à JaLHyd d'effacer son Nub de la Session
      * @param uid formulaire à supprimer
@@ -632,8 +596,6 @@ export class FormulaireService extends Observable {
                 if (nn.meta && nn.meta.title) {
                     title = nn.meta.title;
                 }
-                // pre-fill language cache (for LinkedValues labels for ex.)
-                await this.loadLocalisation(nn.nub.calcType);
                 await this.createFormulaire(nn.nub.calcType, nn.nub, title); // await guarantees loading order
             }
             // apply settings
diff --git a/src/app/services/internationalisation.service.ts b/src/app/services/internationalisation.service.ts
index 14df039699075e1d427e1cd84958c0f914f7fcd4..451931f1b508a6d8104470a5b855a174053676ae 100644
--- a/src/app/services/internationalisation.service.ts
+++ b/src/app/services/internationalisation.service.ts
@@ -7,6 +7,7 @@ import { ApplicationSetupService } from "./app-setup.service";
 import { HttpService } from "./http.service";
 import { fv, decodeHtml } from "../util";
 import { ServiceFactory } from "./service-factory";
+import { FormulaireService } from "./formulaire.service";
 
 @Injectable()
 export class I18nService extends Observable implements Observer {
@@ -20,8 +21,8 @@ export class I18nService extends Observable implements Observer {
     /** localized messages */
     private _Messages: StringMap;
 
-    /** localized messages in fallback language (the one in the config file) */
-    private _fallbackMessages: StringMap;
+    /** to avoid loading language files multiple times */
+    private _languageCache = {};
 
     constructor(
         private applicationSetupService: ApplicationSetupService,
@@ -32,10 +33,6 @@ export class I18nService extends Observable implements Observer {
             fr: "Français",
             en: "English"
         };
-        // load fallback language messages once for all
-        this.httpGetMessages(this.applicationSetupService.fallbackLanguage).then((res: any) => {
-            this._fallbackMessages = res;
-        });
         // add language preferences observer
         this.applicationSetupService.addObserver(this);
     }
@@ -52,6 +49,10 @@ export class I18nService extends Observable implements Observer {
         return this._Messages;
     }
 
+    public get languageCache() {
+        return this._languageCache;
+    }
+
     /**
      * Defines the current language code from its ISO 639-1 code (2 characters) or locale code
      * (ex: "fr", "en", "fr_FR", "en-US")
@@ -69,12 +70,56 @@ export class I18nService extends Observable implements Observer {
         if (this._currentLanguage !== code) {
             this._currentLanguage = code;
             this._Messages = undefined;
-            // reload all messages
+            // reload all messages: global lang files, plus lang files for all calculators !
             const that = this;
-            this.httpGetMessages(code).then((res: any) => {
-                that._Messages = res;
-                // propagate language change to all application
-                that.notifyObservers(undefined);
+            const promisesList: Promise<any>[] = [];
+            for (const ct in CalculatorType) {
+                const calcType = Number(ct);
+                if (!isNaN(calcType)) {
+                    promisesList.push(this.loadLocalisation(calcType).catch((err) => { /* silent fail */ }));
+                }
+            }
+            Promise.all(promisesList).then(() => {
+                this.httpGetMessages(code).then((res: any) => {
+                    that._Messages = res;
+                    // propagate language change to all application
+                    that.notifyObservers(undefined);
+                });
+            });
+        }
+    }
+
+    /**
+     * Loads the localisation file dedicated to calculator type ct; uses cache if available
+     */
+    public loadLocalisation(calc: CalculatorType): Promise<any> {
+        const lang = this.currentLanguage;
+        return this.loadLocalisationForLang(calc, lang).then((localisation) => {
+            return localisation as StringMap;
+        }).catch((e) => {
+            return "";
+        });
+    }
+
+    /**
+     * Loads the localisation file dedicated to calculator type ct for language lang;
+     * keeps it in cache for subsequent calls ()
+     */
+    private loadLocalisationForLang(calc: CalculatorType, lang: string): Promise<any> {
+        const ct = String(calc);
+        // if not already in cache
+        if (! Object.keys(this._languageCache).includes(ct) || ! Object.keys(this._languageCache[calc]).includes(lang)) {
+            const f: string = FormulaireService.getConfigPathPrefix(calc) + lang + ".json";
+            return this.httpService.httpGetRequestPromise(f).then((localisation) => {
+                this._languageCache[ct] = this._languageCache[ct] || {};
+                this._languageCache[ct][lang] = localisation;
+                return localisation as StringMap;
+            }).catch((e) => {
+                throw new Error(`LOCALISATION_FILE_NOT_FOUND "${f}"`);
+            });
+        } else {
+            return new Promise((resolve, reject) => {
+                resolve(); // does nothing but complies with Promise expectation
             });
         }
     }
@@ -107,31 +152,23 @@ export class I18nService extends Observable implements Observer {
      * In production mode, looks in different messages collections :
      *  1. ${msg} if provided
      *  2. messages for current language
-     *  3. messages for fallback language
      *
      * In dev mode, looks only in 1. if provided, else only in 2. which makes missing
      * translations easier to detect
      *
      * @param textKey id du texte (ex: "ERROR_PARAM_NULL")
      */
-    public localizeText(textKey: string, msg?: StringMap) {
-        const messages = msg || this._Messages;
-        if (! messages) {
+    public localizeText(textKey: string) {
+        if (! this._Messages) {
             return `*** messages not loaded: ${this._currentLanguage} ***`;
         }
-        if (messages[textKey] !== undefined) {
-            return decodeHtml(messages[textKey]);
+        if (this._Messages[textKey] !== undefined) {
+            return decodeHtml(this._Messages[textKey]);
         } else {
             // try general message
-            if (msg !== undefined && this._Messages["INFO_LIB_" + textKey.toUpperCase()] !== undefined) {
+            if (this._Messages !== undefined && this._Messages["INFO_LIB_" + textKey.toUpperCase()] !== undefined) {
                 return decodeHtml(this._Messages["INFO_LIB_" + textKey.toUpperCase()]);
             }
-            if (!isDevMode()) {
-                // try fallback language before giving up
-                if (this._fallbackMessages[textKey] !== undefined) {
-                    return decodeHtml(this._fallbackMessages[textKey]);
-                }
-            }
             return `*** message not found: ${textKey} ***`;
         }
     }
@@ -285,7 +322,8 @@ export class I18nService extends Observable implements Observer {
     // interface Observer
 
     /**
-     * Should only be triggered once at app startup, when setup service tries loading language
+     * Should only be triggered once at app startup, when setup service tries loading language,
+     * then everytime language is changed through Preferences screen
      * @param sender should always be ApplicationSetupService
      * @param data object {
      *                  action: should always be "languagePreferenceChanged"
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 073d7138d12380cb0023801844110803907ef295..acbc4c1501bac560a985122e6d8a3223e51bb0e3 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -57,15 +57,20 @@
     "ERROR_REMOUS_PAS_CALCUL": "No possible calculation, neither from upstream nor from downstream",
     "ERROR_REMOUS_PENTE_FORTE": "The water line slope is too steep at abscissa %x% m (the discretisation step should be reduced)",
     "ERROR_RU_CIRC_LEVEL_TOO_HIGH": "Uniform flow cannot be calculated with a pipe under load",
+    "ERROR_NEWTON_NON_CONVERGENCE": "Non-convergence (Newton's method)",
     "ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCONJUG": "Non-convergence of the calculation of the combined depth (Newton's method)",
     "ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE": "Non-convergence of the calculation of the critical depth (Newton's method)",
     "ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCOR": "Non convergence of the calculation of the corresponding elevation (Newton's method)",
     "ERROR_SECTION_NON_CONVERGENCE_NEWTON_HNORMALE": "Non convergence of the calculation of the normal depth (Newton's method)",
     "ERROR_SECTION_PENTE_NEG_NULLE_HNORMALE_INF": "The slope is negative or zero, the normal depth is infinite",
+    "ERROR_SECTION_PERIMETRE_NUL": "Section: calculation is impossible when perimeter is null",
+    "ERROR_SECTION_RAYON_NUL": "Section: calculation is impossible when radius is null",
     "ERROR_SECTION_SURFACE_NULLE": "Section: calculation is impossible when surface is null",
     "ERROR_SOMETHING_FAILED_IN_CHILD": "Calculation of child module #%number% failed",
     "ERROR_SOLVEUR_NO_VARIATED_PARAMS_ALLOWED": "Solver cannot be used with a modules chain containing variated parameters",
     "ERROR_STRUCTURE_Q_TROP_ELEVE": "The flow passing through the other devices is too high: the requested parameter is not calculable.",
+    "ERROR_STRUCTURE_ZDV_PAS_CALCULABLE": "Parameter \"Crest elevation\" cannot be calculated with this discharge law",
+    "ERROR_STRUCTURE_Z_EGAUX_Q_NON_NUL": "Upstream and downstream elevations are equal but flow is not null",
     "INFO_CALCULATOR_CALC_NAME": "Calculator name",
     "INFO_CALCULATOR_CALCULER": "Compute",
     "INFO_CALCULATOR_CLONE": "Duplicate",
@@ -604,6 +609,7 @@
     "INFO_VERIF_OK": "Crossing criteria are met for all species",
     "INFO_VERIF_VARYING_OK": "Crossing criteria are met for all species and all pass modalities",
     "WARNING_VERIF_OK_BUT": "Crossing criteria are met for all species, but there are warnings",
+    "WARNING_VERIF_VARYING_OK_BUT": "Only certain modalities of the pass are crossable",
     "INFO_VERIFICATEUR_CUSTOM_SPECIES": "Custom species: %s",
     "INFO_VERIFICATEUR_SPECIES_GROUP": "Species group",
     "INFO_VERIFICATEUR_TITRE": "Fish pass verification",
@@ -626,6 +632,7 @@
     "WARNING_GRILLE_ALPHA_GREATER_THAN_45": "Recommendation for fish guiding: α ≤ 45°",
     "WARNING_GRILLE_BETA_GREATER_THAN_26": "Recommendation for fish guiding: β ≤ 26°",
     "WARNING_GRILLE_VN_GREATER_THAN_05": "Recommendation to prevent fish getting stuck on grid plan (physical barrier) or prematurely passing through the grid (behavioural barrier): VN ≤ 0.5 m/s.<br>Above average value calculated here, refer to the recommendations taken from experimental caracterisation of effective speed values.",
+    "WARNING_GRILLE_O_LOWER_THAN_OB": "Total obstruction (entered) is lower than obstruction due to bars only (calculated)",
     "WARNING_LECHAPT_CALMON_SPEED_OUTSIDE_04_2": "This formula is discouraged for a speed that is not between 0.4 and 2 m/s",
     "WARNING_UPSTREAM_BOTTOM_HIGHER_THAN_WATER": "Upstream water elevation is lower or equal to bottom elevation",
     "WARNING_DOWNSTREAM_BOTTOM_HIGHER_THAN_WATER": "Downstream water elevation is lower or equal to bottom elevation",
@@ -656,6 +663,7 @@
     "INFO_PARENT_PREFIX": "%name% #%position%: ",
     "INFO_PARENT_PREFIX_DOWNWALL": "downwall: ",
     "ERROR_VERIF_ERRORS_IN_PASS": "Pass to verify contains errors",
+    "ERROR_VERIF_VARYING_ERRORS_IN_PASS": "Pass to verify contains error at iteration %i%",
     "ERROR_VERIF_MISSING_CRITERION": "Criterion %var_criterion% must be defined",
     "ERROR_VERIF_MR_VMAX": "Maximum speed %V% too high (maximum: %maxV%)",
     "ERROR_VERIF_MR_PVMAX": "Dissipated power %PV% too high (maximum: %maxPV%)",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 58d8ec44e8d920398dc794ef354654bf8970ce2d..2fe2697aaa909d0f891524bba0fede5a4fbe4684 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -57,15 +57,20 @@
     "ERROR_REMOUS_PAS_CALCUL": "Aucun calcul possible ni depuis l'amont ni depuis l'aval",
     "ERROR_REMOUS_PENTE_FORTE": "La pente de la ligne d'eau est trop forte à l'abscisse %x% m (il faudrait réduire le pas de discrétisation)",
     "ERROR_RU_CIRC_LEVEL_TOO_HIGH": "Le régime uniforme ne peut pas être calculé avec une conduite en charge",
+    "ERROR_NEWTON_NON_CONVERGENCE": "Non convergence (Méthode de Newton)",
     "ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCONJUG": "Non convergence du calcul de la hauteur conjuguée (Méthode de Newton)",
     "ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCRITIQUE": "Non convergence du calcul de la hauteur critique (Méthode de Newton)",
     "ERROR_SECTION_NON_CONVERGENCE_NEWTON_HCOR": "Non convergence du calcul de la hauteur correspondante (Méthode de Newton)",
     "ERROR_SECTION_NON_CONVERGENCE_NEWTON_HNORMALE": "Non convergence du calcul de la hauteur normale (Méthode de Newton)",
     "ERROR_SECTION_PENTE_NEG_NULLE_HNORMALE_INF": "La pente est négative ou nulle, la hauteur normale est infinie",
+    "ERROR_SECTION_PERIMETRE_NUL": "Section&nbsp;: calcul impossible à cause d'un périmètre nul",
+    "ERROR_SECTION_RAYON_NUL": "Section&nbsp;: calcul impossible à cause d'un rayon nul",
     "ERROR_SECTION_SURFACE_NULLE": "Section&nbsp;: calcul impossible à cause d'une surface nulle",
     "ERROR_SOMETHING_FAILED_IN_CHILD": "Le calcul du module enfant n°%number% a échoué",
     "ERROR_SOLVEUR_NO_VARIATED_PARAMS_ALLOWED": "Le solveur ne peut pas être utilisé avec une chaîne de modules contenant des paramètres variés",
     "ERROR_STRUCTURE_Q_TROP_ELEVE": "Le débit passant par les autres ouvrages est trop élevé&nbsp;: le paramètre demandé n'est pas calculable.",
+    "ERROR_STRUCTURE_ZDV_PAS_CALCULABLE": "Le paramètre \"Cote de radier\" ne peut pas être calculé avec cette loi de débit",
+    "ERROR_STRUCTURE_Z_EGAUX_Q_NON_NUL": "Les cotes amont aval sont égales et le débit n'est pas nul",
     "INFO_CALCULATOR_CALC_NAME": "Nom du module de calcul",
     "INFO_CALCULATOR_CALCULER": "Calculer",
     "INFO_CALCULATOR_CLONE": "Dupliquer",
@@ -628,6 +633,7 @@
     "WARNING_GRILLE_ALPHA_GREATER_THAN_45": "Préconisation pour le guidage des poissons&nbsp;: α ≤ 45°",
     "WARNING_GRILLE_BETA_GREATER_THAN_26": "Préconisation pour le guidage des poissons&nbsp;: β ≤ 26°",
     "WARNING_GRILLE_VN_GREATER_THAN_05": "Préconisation pour éviter le placage des poissons sur le plan de grille (barrière physique) ou leur passage prématuré au travers (barrière comportementale)&nbsp;: VN ≤ 0.5 m/s.<br>Au-delà de la valeur moyenne calculée ici, se reporter aux préconisations tirées de la caractérisation expérimentale des valeurs effectives de vitesses.",
+    "WARNING_GRILLE_O_LOWER_THAN_OB": "L'obstruction totale (saisie) est inférieure à l'obstruction due aux barreaux seulement (calculée)",
     "WARNING_LECHAPT_CALMON_SPEED_OUTSIDE_04_2": "Cette formule n'est pas conseillée pour une vitesse non comprise entre 0.4 et 2 m/s",
     "WARNING_UPSTREAM_BOTTOM_HIGHER_THAN_WATER": "La cote de l'eau à l'amont est plus basse ou égale à la cote de fond",
     "WARNING_DOWNSTREAM_BOTTOM_HIGHER_THAN_WATER": "La cote de l'eau à l'aval est plus basse ou égale à la cote de fond",