diff --git a/DEVELOPERS.md b/DEVELOPERS.md
index d5d7cb3a7a7d098ea85ca6892957746fe5f048e9..207e7687ef0e0a1db871490ab3023fe1d1f9f812 100644
--- a/DEVELOPERS.md
+++ b/DEVELOPERS.md
@@ -270,7 +270,7 @@ case CalculatorType.MacroRugoCompound:
 
 Les listes déroulantes sont toujours associées à des **propriétés** du Nub.
 
-En général les valeurs autorisées sont tirées de l'**enum** correspondant, d'après le tableau `Session.enumFromProperty` de JaLHyd. Pour les autres cas, voir "si la liste n'est pas associée à un enum" ci-dessous.
+En général les valeurs autorisées sont tirées de l'**enum** correspondant, d'après le tableau `Session.enumFromProperty` de JaLHyd. Pour les autres cas, voir les paragraphes "si la liste est associée à…" ci-dessous.
 
 #### configuration
 
@@ -309,7 +309,7 @@ Dans le fichier de configuration du module, ajouter la définition des listes d
  
 Une liste déroulante peut être associée à une **source**, qui détermine quels sont les choix possibles.
 
-Pour ajouter une source, modifier la méthode `parseConfig()` de la classe `SelectField`, dans le fichier `src/app/formulaire/elements/select-field.ts`.
+Pour ajouter une source, modifier la méthode `loadEntriesFromSource()` de la classe `SelectField`, dans le fichier `src/app/formulaire/elements/select-field.ts`.
 
 Exemple pour la source "remous_target" associée à la propriété "varCalc", dans le module CourbeRemous :
 
diff --git a/e2e/check-translations.e2e-spec.ts b/e2e/check-translations.e2e-spec.ts
index ddcd763d363899deed0de4c3cd7bfcab52bc40ce..e74d7f21004f417559d4d21aa7f541a811c35505 100644
--- a/e2e/check-translations.e2e-spec.ts
+++ b/e2e/check-translations.e2e-spec.ts
@@ -77,11 +77,7 @@ describe("ngHyd − check translation of all calculators", () => {
           }
 
           // check absence of "*** message not found" in whole DOM
-          const ps = await browser.getPageSource();
-          expect(ps).not.toContain("*** message not found");
-          /* const pos = ps.indexOf("*** message not found");
-          const bout = ps.substring(pos - 50, pos + 50);
-          console.log("------------ BOUT ---------------", bout); */
+          expect(await browser.getPageSource()).not.toContain("*** message not found", "missing translations found");
 
           // empty session
           await navBar.clickMenuButton();
diff --git a/src/app/calculators/solveur/config.json b/src/app/calculators/solveur/config.json
index fa1da444fcb444a1f7418c60118b999565ffb87c..03262ac7d9120f865f2d8b225f01b1d522eef6c9 100644
--- a/src/app/calculators/solveur/config.json
+++ b/src/app/calculators/solveur/config.json
@@ -5,8 +5,7 @@
         "fields": [
             {
                 "id": "select_target_nub",
-                "type": "select_reference",
-                "reference": "nub",
+                "type": "select_custom",
                 "source": "solveur_target"
             },
             {
@@ -25,8 +24,7 @@
         "fields": [
             {
                 "id": "select_searched_param",
-                "type": "select_reference",
-                "reference": "parameter",
+                "type": "select_custom",
                 "source": "solveur_searched"
             },
             "Xinit"
diff --git a/src/app/calculators/verificateur/config.json b/src/app/calculators/verificateur/config.json
index 5b03751eda6393520a76969e37a8c169ce5dc25f..8ec8d41caf8aef98f29807dbb55cca905f00a9ac 100644
--- a/src/app/calculators/verificateur/config.json
+++ b/src/app/calculators/verificateur/config.json
@@ -5,8 +5,7 @@
         "fields": [
             {
                 "id": "select_target_pass",
-                "type": "select_reference",
-                "reference": "nub",
+                "type": "select_custom",
                 "source": "verificateur_target"
             },
             {
@@ -24,6 +23,7 @@
             {
                 "type": "select",
                 "id": "select_species_list",
+                "property": "speciesList",
                 "source": "verificateur_species",
                 "multiple": true
             }
@@ -31,7 +31,7 @@
     },
     {
         "type": "options",
-        "selectIds": [ "select_pab_jet_type" ],
+        "selectIds": [ "select_pab_jet_type", "select_species_list" ],
         "targetPassSelectId": "select_target_pass",
         "speciesListSelectId": "select_species_list",
         "help": "verification/verificateur.html"
diff --git a/src/app/components/select-field-line/select-field-line.component.ts b/src/app/components/select-field-line/select-field-line.component.ts
index f2c43341da3dddd48d88d66c2dd2a0ecf95fc468..c432c19e787e147f69437aaf599be10d26602fe4 100644
--- a/src/app/components/select-field-line/select-field-line.component.ts
+++ b/src/app/components/select-field-line/select-field-line.component.ts
@@ -3,8 +3,8 @@ import { Component, Input, OnInit } from "@angular/core";
 import { SelectField } from "../../formulaire/elements/select-field";
 import { SelectEntry } from "../../formulaire/elements/select-entry";
 import { I18nService } from "../../services/internationalisation.service";
-import { SelectFieldReference } from "../../formulaire/elements/select-field-reference";
 import { ApplicationSetupService } from "../../services/app-setup.service";
+import { SelectFieldCustom } from "../../formulaire/elements/select-field-custom";
 
 @Component({
     selector: "select-field-line",
@@ -115,9 +115,7 @@ export class SelectFieldLineComponent implements OnInit {
 
     // called every time we navigate to the module
     ngOnInit(): void {
-        console.log("> ngOnInit()", this.selectId);
-        if (this._select instanceof SelectFieldReference) {
-            console.log(">> updateEntries() !", this.selectId);
+        if (this._select instanceof SelectFieldCustom) {
             this._select.updateEntries();
         }
     }
diff --git a/src/app/formulaire/definition/form-solveur.ts b/src/app/formulaire/definition/form-solveur.ts
index b6987a5d5ee756ebf556c71dee6f19f5a915604e..fad442e8512f35b90792eb4e14f6ace9a85f46d0 100644
--- a/src/app/formulaire/definition/form-solveur.ts
+++ b/src/app/formulaire/definition/form-solveur.ts
@@ -1,7 +1,6 @@
 import { IObservable, ParamDefinition, Nub } from "jalhyd";
 
-import { SelectFieldNub } from "../elements/select-field-nub";
-import { SelectFieldParameter } from "../elements/select-field-parameter";
+import { SelectFieldCustom } from "../elements/select-field-custom";
 import { NgParameter } from "../elements/ngparam";
 import { FormulaireFixedVar } from "./form-fixedvar";
 import { SelectField } from "../elements/select-field";
@@ -36,7 +35,7 @@ export class FormulaireSolveur extends FormulaireFixedVar {
                 sel.addObserver(this);
                 if (firstNotif) {
                     // force 1st observation
-                    (sel as SelectFieldNub).notifySelectValueChanged();
+                    (sel as SelectFieldCustom).notifyValueChanged();
                 }
             }
         }
@@ -56,7 +55,7 @@ export class FormulaireSolveur extends FormulaireFixedVar {
                 sel.addObserver(this);
                 if (firstNotif) {
                     // force 1st observation
-                    (sel as SelectFieldNub).notifySelectValueChanged();
+                    (sel as SelectFieldCustom).notifyValueChanged();
                 }
             }
         }
@@ -80,8 +79,8 @@ export class FormulaireSolveur extends FormulaireFixedVar {
             this.reset();
         }
 
-        if (sender instanceof SelectFieldNub) {
-            if (data.action === "select") {
+        if (sender instanceof SelectFieldCustom) {
+            if (sender.id === "select_target_nub" && data.action === "select") {
                 // update Solveur property: Nub to calculate
                 try {
                     // if searchedParam is set to a value that won't be available anymore
@@ -98,9 +97,7 @@ export class FormulaireSolveur extends FormulaireFixedVar {
                 }
                 // refresh parameters selector
                 this.refreshParameterEntries();
-            }
-        } else if (sender instanceof SelectFieldParameter) {
-            if (data.action === "select") {
+            } else if (sender.id === "select_searched_param" && data.action === "select") {
                 // update Solveur property: searched Parameter
                 try {
                     const p: ParamDefinition = data.value.value;
@@ -125,7 +122,7 @@ export class FormulaireSolveur extends FormulaireFixedVar {
      * Re-populate searched parameter selector with fresh entries
      */
     private refreshParameterEntries() {
-        const pSel = this.getFormulaireNodeById(this._searchedParamSelectId) as SelectFieldParameter;
+        const pSel = this.getFormulaireNodeById(this._searchedParamSelectId) as SelectFieldCustom;
         if (pSel) {
             pSel.updateEntries();
             // reflect changes in GUI
diff --git a/src/app/formulaire/definition/form-verificateur.ts b/src/app/formulaire/definition/form-verificateur.ts
index 50560319a8a37fff9cb39fc273ddb48134035a81..b7253882286a2c7282e287359b9835ebcbc825fd 100644
--- a/src/app/formulaire/definition/form-verificateur.ts
+++ b/src/app/formulaire/definition/form-verificateur.ts
@@ -1,7 +1,8 @@
-import { IObservable, Nub } from "jalhyd";
+import { IObservable, Nub, Verificateur } from "jalhyd";
 
-import { SelectFieldNub } from "../elements/select-field-nub";
+import { SelectFieldCustom } from "../elements/select-field-custom";
 import { FormulaireFixedVar } from "./form-fixedvar";
+import { SelectField } from '../elements/select-field';
 
 /**
  * Formulaire pour les Vérificateurs
@@ -16,7 +17,7 @@ export class FormulaireVerificateur extends FormulaireFixedVar {
 
     protected parseOptions(json: {}) {
         super.parseOptions(json);
-        this._targetPassSelectId = this.getOption(json, "targetPassSelectI");
+        this._targetPassSelectId = this.getOption(json, "targetPassSelectId");
         this._speciesListSelectId = this.getOption(json, "speciesListSelectId");
     }
 
@@ -28,21 +29,10 @@ export class FormulaireVerificateur extends FormulaireFixedVar {
                 sel.addObserver(this);
                 if (firstNotif) {
                     // force 1st observation
-                    (sel as SelectFieldNub).notifySelectValueChanged();
+                    (sel as SelectFieldCustom).notifyValueChanged();
                 }
             }
         }
-        if (this._speciesListSelectId) {
-            const sel = this.getFormulaireNodeById(this._speciesListSelectId);
-            /* if (sel) {
-                sel.addObserver(this);
-                if (firstNotif) {
-                    // force 1st observation
-                    (sel as SelectFieldNub).notifySelectValueChanged();
-                }
-            } */
-        }
-
     }
 
     // interface Observer
@@ -62,30 +52,30 @@ export class FormulaireVerificateur extends FormulaireFixedVar {
             this.reset();
         }
 
-        if (sender instanceof SelectFieldNub) {
+        console.log("> update", data, sender.constructor.name);
+
+        if (sender instanceof SelectFieldCustom) {
             if (data.action === "select") {
                 // update Verificateur property: Pass to check
-                this._currentNub.properties.setPropValue("nubToVerify", data.value.value);
+                let v = undefined;
+                if (data && data.value && data.value.value) {
+                    v = data.value.value;
+                }
+                this._currentNub.properties.setPropValue("nubToVerify", data.value);
                 // @TODO refresh jet type selector
             }
-        }/*  else if (sender instanceof SelectField) {
-            if (sender.id === "select_target_result") {
-                // refresh parameters selector
-                this.refreshParameterEntries();
-            }
-        } */
+        }
     }
 
-    /**
-     * Re-populate searched parameter selector with fresh entries
-     */
-    /* private refreshParameterEntries() {
-        const pSel = this.getFormulaireNodeById(this._speciesListSelectId) as SelectFieldParameter;
+    public onCalculatorInit() {
+        // refresh species list selector on each display, because Session might have gained new Espece nubs
+        console.log(">>>> speciesList avant rafraîchissement :", (this.currentNub as Verificateur).speciesList);
+        const pSel = this.getFormulaireNodeById(this._speciesListSelectId) as SelectField;
         if (pSel) {
-            pSel.updateEntries();
-            // reflect changes in GUI
-            const inputYtarget = this.getFormulaireNodeById("Ytarget") as NgParameter;
-            inputYtarget.notifyValueModified(this);
+            /* pSel.clearEntries();
+            pSel.parseConfig(); */
+            // (pSel.parent as FieldSet).updateFields()
         }
-    } */
+    }
+
 }
diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts
index 3e3b2714db410ebf1f7ec28c25c9f2d4066a7deb..13ee41a8d95e66a4717d930af421803699692010 100644
--- a/src/app/formulaire/elements/fieldset.ts
+++ b/src/app/formulaire/elements/fieldset.ts
@@ -13,8 +13,7 @@ import { SelectField } from "./select-field";
 import { NgParameter, ParamRadioConfig } from "./ngparam";
 import { StringMap } from "../../stringmap";
 import { FieldsetContainer } from "./fieldset-container";
-import { SelectFieldNub } from "./select-field-nub";
-import { SelectFieldParameter } from "./select-field-parameter";
+import { SelectFieldCustom } from "./select-field-custom";
 import { FormulaireFixedVar } from "../definition/form-fixedvar";
 import { SelectEntry } from './select-entry';
 
@@ -84,23 +83,12 @@ export class FieldSet extends FormulaireElement implements Observer {
         return res;
     }
 
-    private parse_select_reference(json: {}): SelectField {
-        const refType = json["reference"];
+    private parse_select_custom(json: {}): SelectField {
         const source = json["source"];
-        let res: SelectField;
         if (source === undefined || source === "") {
-            throw new Error(`Fieldset.parse_select_reference(): "source" must not be empty`);
-        }
-        switch (refType) {
-            case "nub": // @TODO upstreamNub / downstreamNub ?
-                res = new SelectFieldNub(this, source);
-                break;
-            case "parameter":
-                res = new SelectFieldParameter(this, source);
-                break;
-            default:
-                throw new Error(`Fieldset.parse_select_reference(): unknown reference type ${refType}`);
+            throw new Error(`Fieldset.parse_select_custom(): "source" must not be empty`);
         }
+        const res: SelectField = new SelectFieldCustom(this);
         res.parseConfig(json);
         res.addObserver(this);
         return res;
@@ -198,8 +186,8 @@ export class FieldSet extends FormulaireElement implements Observer {
                     this.addField(param);
                     break;
 
-                case "select_reference":
-                    param = this.parse_select_reference(field);
+                case "select_custom":
+                    param = this.parse_select_custom(field);
                     this.addField(param);
                     break;
 
@@ -391,7 +379,12 @@ export class FieldSet extends FormulaireElement implements Observer {
                                     const fe = this.parentForm.getFieldById(sId);
                                     if (fe && data.value !== undefined) {
                                         const prop = (fe as SelectField).associatedProperty;
-                                        this.setPropValue(prop, data.value.value);
+                                        // for multiple select
+                                        if (Array.isArray(data.value)) {
+                                            this.setPropValue(prop, data.value.map((v: any) => v.value));
+                                        } else {
+                                            this.setPropValue(prop, data.value.value);
+                                        }
                                     }
                                 }
                             }
diff --git a/src/app/formulaire/elements/select-field-custom.ts b/src/app/formulaire/elements/select-field-custom.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6c57eba105229a228bf06798eb654df23999a7ba
--- /dev/null
+++ b/src/app/formulaire/elements/select-field-custom.ts
@@ -0,0 +1,216 @@
+import { SelectEntry } from "./select-entry";
+import { ServiceFactory } from "../../services/service-factory";
+import { decodeHtml, arraysAreEqual } from "../../util";
+
+import { Session, Solveur, FishPass, CalculatorType, Verificateur, Nub } from "jalhyd";
+import { SelectField } from './select-field';
+
+/**
+ * A select field that populates itself with custom stuff (ex: references to Nubs, Parameters…)
+ */
+export class SelectFieldCustom extends SelectField {
+
+    /**
+     * Loads UI with the value held by the model
+     */
+    protected initSelectedValue() {
+        const nub = this.parentForm.currentNub;
+        console.log("[X] I S V", nub.constructor.name, this.source);
+        switch (this.source) {
+
+            case "solveur_target": // Solveur, module cible (à calculer)
+                const ntc = (nub as Solveur).nubToCalculate;
+                if (ntc !== undefined) {
+                    this.setValueFromId(this._entriesBaseId + ntc.uid);
+                }
+                break;
+
+            case "solveur_searched": // Solveur, paramètre recherché (à faire varier)
+                const sp = (nub as Solveur).searchedParameter;
+                if (sp !== undefined) {
+                    this.setValueFromId(this._entriesBaseId + sp.nubUid + "_" + sp.symbol);
+                }
+                break;
+
+            case "verificateur_target": // Vérificateur, passe cible (à vérifier)
+                const ntv = (nub as Verificateur).nubToVerify;
+                if (ntv !== undefined) {
+                    this.setValueFromId(this._entriesBaseId + ntv.uid);
+                }
+                break;
+        }
+    }
+
+    /**
+     * Populates entries with available options
+     */
+    protected populate() {
+        const fs = ServiceFactory.instance.formulaireService;
+        let candidateNubs: any[];
+        switch (this.source) {
+
+            case "solveur_target": // Solveur, module cible (à calculer)
+                // find all Nubs having at least one link to another Nub's result
+                candidateNubs =
+                    Session.getInstance().getDownstreamNubs().concat(
+                        Session.getInstance().getUpstreamNubsHavingExtraResults()
+                    ).filter(
+                        (element, index, self) => self.findIndex((e) => e.uid === element.uid) === index
+                    );
+                for (const cn of candidateNubs) {
+                    const nub = fs.getFormulaireFromId(cn.uid);
+                    if (nub) {
+                        const calc = nub.calculatorName;
+                        let label = calc;
+                        // calculated param
+                        if (cn.calculatedParam !== undefined) {
+                            const varName = fs.expandVariableName(cn.calcType, cn.calculatedParam.symbol);
+                            label += ` / ${varName} (${cn.calculatedParam.symbol})`;
+                        }
+                        this.addEntry(new SelectEntry(this._entriesBaseId + cn.uid, cn.uid, decodeHtml(label)));
+                    } else {
+                        // silent fail, this Solveur nub was probably loaded before all the candidate nubs are done loading
+                    }
+                }
+                break;
+
+            case "solveur_searched": // Solveur, paramètre recherché (à faire varier)
+                // find all non-calculated, non-linked parameters of all Nubs that
+                // the current "target" Nub depends on (if any)
+                const solv = this.parentForm.currentNub as Solveur;
+                const ntc: Nub = solv.nubToCalculate;
+                const searchableParams = Solveur.getDependingNubsSearchableParams(
+                    ntc,
+                    solv.targettedResult !== undefined && solv.targettedResult !== ""
+                );
+                for (const p of searchableParams) {
+                    if (p.visible) {
+                        const calc = fs.getFormulaireFromId(p.originNub.uid).calculatorName;
+                        const varName = fs.expandVariableName(p.originNub.calcType, p.symbol);
+                        const label = `${p.symbol} - ${varName} (${calc})`;
+                        this.addEntry(new SelectEntry(this._entriesBaseId + p.originNub.uid + "_" + p.symbol, p, decodeHtml(label)));
+                    }
+                }
+                break;
+
+            case "verificateur_target": // Vérificateur, passe cible (à vérifier)
+                // find all Nubs of type FishPass
+                candidateNubs = Session.getInstance().getAllNubs().filter((element) => {
+                    return (
+                        (element instanceof FishPass)
+                        && element.calcType !== CalculatorType.Par // ParSimulation extends Par @TODO find something better
+                    );
+                });
+                for (const cn of candidateNubs) {
+                    const nub = fs.getFormulaireFromId(cn.uid);
+                    if (nub) {
+                        const label = nub.calculatorName + " (" + fs.getLocalisedTitleFromCalculatorType(nub.calculatorType) + ")";
+                        this.addEntry(new SelectEntry(this._entriesBaseId + cn.uid, cn.uid, decodeHtml(label)));
+                    } else {
+                        // silent fail, this Verificateur nub was probably loaded before all the candidate nubs are done loading
+                    }
+                }
+                break;
+
+        }
+    }
+
+    protected setDefaultValue() {
+        // default to first available entry if any
+        if (this._entries.length > 0) {
+            if (this._multiple) {
+                this.setValue([ this._entries[0] ]);
+            } else {
+                this.setValue(this._entries[0]);
+            }
+        } else {
+            // notify observers that no value is selected anymore
+            this.notifyValueChanged();
+        }
+    }
+
+    /**
+     * Once config is parsed, init original value from model
+     * (needs config, for this._entriesBaseId to be set)
+     */
+    protected afterParseConfig() {
+        this.populate();
+        this.initSelectedValue();
+    }
+
+    /**
+     * Reloads available entries, trying to keep the current selected
+     * value; does not notify observers if value did not change
+     */
+    public updateEntries() {
+        // store previous selected entry
+        const pse = this._selectedEntry;
+        // empty
+        this.clearEntries();
+        // populate
+        this.populate();
+        // if no entry is available anymore, unset value
+        if (this.entries.length === 0) {
+            if (this.multiple) {
+                super.setValue([]);
+            } else {
+                super.setValue(undefined);
+            }
+        } else {
+            // keep previously selected entry if possible @TODO manage multiple values
+            if (pse && ! Array.isArray(pse) && pse.id) {
+                this.setValueFromId(pse.id);
+            } else {
+                this.setDefaultValue();
+            }
+        }
+    }
+
+    /**
+     * Updates selectedValue; notifies observers only if
+     * value.id has changed
+     */
+    public setValue(v: SelectEntry | SelectEntry[]) {
+        const previousSelectedEntry = this._selectedEntry;
+        this._selectedEntry = v;
+        // if value changed
+        let valueChanged = (
+            ! previousSelectedEntry
+            || (
+                ! Array.isArray(previousSelectedEntry)
+                && ! Array.isArray(v)
+                && previousSelectedEntry.id !== v.id
+            )
+            || (
+                Array.isArray(previousSelectedEntry)
+                && Array.isArray(v)
+                && arraysAreEqual(previousSelectedEntry, v, "id", true)
+            )
+        );
+        if (valueChanged) {
+            this.notifyValueChanged();
+        }
+    }
+
+    /**
+     * Sets value from given ID; if it was not found, sets the
+     * first available entry as selectedValue
+     */
+    public setValueFromId(id: string) {
+        let found = false;
+        for (const e of this._entries) {
+            if (e.id === id) {
+                found = true;
+                if (this._multiple) {
+                    this.setValue([ e ]);
+                } else {
+                    this.setValue(e);
+                }
+            }
+        }
+        if (! found) {
+            this.setDefaultValue();
+        }
+    }
+
+}
diff --git a/src/app/formulaire/elements/select-field-nub.ts b/src/app/formulaire/elements/select-field-nub.ts
deleted file mode 100644
index 9942f160fb3efb461cb51fd7d8b24a1c6b7dc64b..0000000000000000000000000000000000000000
--- a/src/app/formulaire/elements/select-field-nub.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { SelectFieldReference } from "./select-field-reference";
-import { SelectEntry } from "./select-entry";
-import { ServiceFactory } from "../../services/service-factory";
-import { decodeHtml } from "../../util";
-
-import { Session, Solveur, FishPass, CalculatorType } from "jalhyd";
-
-/**
- * A select field that populates itself with references to Nubs
- */
-export class SelectFieldNub extends SelectFieldReference {
-
-    protected initSelectedValue() {
-        const nub = this.parentForm.currentNub;
-        if (nub instanceof Solveur) {
-            const ntc = nub.nubToCalculate;
-            if (ntc !== undefined) {
-                this.setValueFromId(this._entriesBaseId + ntc.uid);
-            }
-        }
-    }
-
-    /**
-     * Populates entries with available references
-     */
-    protected populate() {
-        const fs = ServiceFactory.instance.formulaireService;
-        let candidateNubs: any[];
-        switch (this._source) {
-            case "solveur_target": // Solveur, module cible (à calculer)
-                // find all Nubs having at least one link to another Nub's result
-                candidateNubs =
-                    Session.getInstance().getDownstreamNubs().concat(
-                        Session.getInstance().getUpstreamNubsHavingExtraResults()
-                    ).filter(
-                        (element, index, self) => self.findIndex((e) => e.uid === element.uid) === index
-                    );
-                for (const cn of candidateNubs) {
-                    const nub = fs.getFormulaireFromId(cn.uid);
-                    if (nub) {
-                        const calc = nub.calculatorName;
-                        let label = calc;
-                        // calculated param
-                        if (cn.calculatedParam !== undefined) {
-                            const varName = fs.expandVariableName(cn.calcType, cn.calculatedParam.symbol);
-                            label += ` / ${varName} (${cn.calculatedParam.symbol})`;
-                        }
-                        this.addEntry(new SelectEntry(this._entriesBaseId + cn.uid, cn.uid, decodeHtml(label)));
-                    } else {
-                        // silent fail, this Solveur nub was probably loaded before all the candidate nubs are done loading
-                    }
-                }
-                break;
-
-            case "verificateur_target": // Vérificateur, passe cible (à vérifier)
-                // find all Nubs of type FishPass
-                candidateNubs = Session.getInstance().getAllNubs().filter((element) => {
-                    return (
-                        (element instanceof FishPass)
-                        && element.calcType !== CalculatorType.Par // ParSimulation extends Par @TODO find something better
-                    );
-                });
-                for (const cn of candidateNubs) {
-                    const nub = fs.getFormulaireFromId(cn.uid);
-                    if (nub) {
-                        const label = nub.calculatorName + " (" + fs.getLocalisedTitleFromCalculatorType(nub.calculatorType) + ")";
-                        this.addEntry(new SelectEntry(this._entriesBaseId + cn.uid, cn.uid, decodeHtml(label)));
-                    } else {
-                        // silent fail, this Verificateur nub was probably loaded before all the candidate nubs are done loading
-                    }
-                }
-                break;
-        }
-    }
-
-}
diff --git a/src/app/formulaire/elements/select-field-parameter.ts b/src/app/formulaire/elements/select-field-parameter.ts
deleted file mode 100644
index c5a9d7291af5589382f0e54ebc698df7ce1cae4f..0000000000000000000000000000000000000000
--- a/src/app/formulaire/elements/select-field-parameter.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { SelectFieldReference } from "./select-field-reference";
-import { SelectEntry } from "./select-entry";
-import { decodeHtml } from "../../util";
-import { ServiceFactory } from "../../services/service-factory";
-
-import { Nub, Solveur } from "jalhyd";
-
-/**
- * A select field that populates itself with references to ParamDefinitions
- */
-export class SelectFieldParameter extends SelectFieldReference {
-
-    protected initSelectedValue() {
-        const nub = this.parentForm.currentNub;
-        if (nub instanceof Solveur) {
-            const sp = nub.searchedParameter;
-            if (sp !== undefined) {
-                this.setValueFromId(this._entriesBaseId + sp.nubUid + "_" + sp.symbol);
-            }
-        }
-    }
-
-    /**
-     * Populates entries with available references
-     */
-    protected populate() {
-        switch (this._source) {
-            case "solveur_searched": // Solveur, paramètre recherché (à faire varier)
-                // find all non-calculated, non-linked parameters of all Nubs that
-                // the current "target" Nub depends on (if any)
-                const fs = ServiceFactory.instance.formulaireService;
-                const solv = this.parentForm.currentNub as Solveur;
-                const ntc: Nub = solv.nubToCalculate;
-                const searchableParams = Solveur.getDependingNubsSearchableParams(
-                    ntc,
-                    solv.targettedResult !== undefined && solv.targettedResult !== ""
-                );
-                for (const p of searchableParams) {
-                    if (p.visible) {
-                        const calc = fs.getFormulaireFromId(p.originNub.uid).calculatorName;
-                        const varName = fs.expandVariableName(p.originNub.calcType, p.symbol);
-                        const label = `${p.symbol} - ${varName} (${calc})`;
-                        this.addEntry(new SelectEntry(this._entriesBaseId + p.originNub.uid + "_" + p.symbol, p, decodeHtml(label)));
-                    }
-                }
-                break;
-        }
-    }
-
-}
diff --git a/src/app/formulaire/elements/select-field-reference.ts b/src/app/formulaire/elements/select-field-reference.ts
deleted file mode 100644
index c4024feea76a86f7aa518dc4fd106f22ab230aae..0000000000000000000000000000000000000000
--- a/src/app/formulaire/elements/select-field-reference.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import { SelectField } from "./select-field";
-import { SelectEntry } from "./select-entry";
-import { FormulaireNode } from "./formulaire-node";
-
-import { arraysAreEqual } from "../../util";
-
-/**
- * A select field that populates itself with references to
- * available objects (for ex. Nub or ParamDefinition)
- */
-export abstract class SelectFieldReference extends SelectField {
-
-    /** source identifier for populate() method */
-    protected _source: string;
-
-    constructor(parent: FormulaireNode, source: string) {
-        super(parent);
-        this._source = source;
-    }
-
-    protected abstract initSelectedValue();
-
-    /**
-     * Populates entries with available references
-     */
-    protected abstract populate();
-
-    /**
-     * Once config is parsed, init original value from model
-     * (needs config, for this._entriesBaseId to be set)
-     */
-    protected afterParseConfig() {
-        this.populate();
-        this.initSelectedValue();
-    }
-
-    /**
-     * Reloads available entries, trying to keep the current selected
-     * value; does not notify observers if value did not change
-     */
-    public updateEntries() {
-        // store previous selected entry
-        const pse = this._selectedEntry;
-        // empty
-        this.clearEntries();
-        // populate
-        this.populate();
-        // if no entry is available anymore, unset value
-        if (this.entries.length === 0) {
-            if (this.multiple) {
-                super.setValue([]);
-            } else {
-                super.setValue(undefined);
-            }
-        } else {
-            // keep previously selected entry if possible @TODO manage multiple values
-            if (pse && ! Array.isArray(pse) && pse.id) {
-                this.setValueFromId(pse.id);
-            } else {
-                this.setDefaultValue();
-            }
-        }
-    }
-
-    /**
-     * Updates selectedValue; notifies observers only if
-     * value.id has changed
-     */
-    public setValue(v: SelectEntry | SelectEntry[]) {
-        const previousSelectedEntry = this._selectedEntry;
-        this._selectedEntry = v;
-        // if value changed
-        let valueChanged = (
-            ! previousSelectedEntry
-            || (
-                ! Array.isArray(previousSelectedEntry)
-                && ! Array.isArray(v)
-                && previousSelectedEntry.id !== v.id
-            )
-            || (
-                Array.isArray(previousSelectedEntry)
-                && Array.isArray(v)
-                && arraysAreEqual(previousSelectedEntry, v, "id", true)
-            )
-        );
-        if (valueChanged) {
-            this.notifySelectValueChanged();
-        }
-    }
-
-    public notifySelectValueChanged() {
-        this.notifyObservers({
-            "action": "select",
-            "value": this._selectedEntry
-        }, this);
-    }
-
-    /**
-     * Sets value from given ID; if it was not found, sets the
-     * first available entry as selectedValue
-     */
-    public setValueFromId(id: string) {
-        let found = false;
-        for (const e of this._entries) {
-            if (e.id === id) {
-                found = true;
-                if (this._multiple) {
-                    this.setValue([ e ]);
-                } else {
-                    this.setValue(e);
-                }
-            }
-        }
-        if (! found) {
-            this.setDefaultValue();
-        }
-    }
-
-    protected setDefaultValue() {
-        // default to first available entry if any
-        if (this._entries.length > 0) {
-            if (this._multiple) {
-                this.setValue([ this._entries[0] ]);
-            } else {
-                this.setValue(this._entries[0]);
-            }
-        } else {
-            // notify observers that no value is selected anymore
-            this.notifySelectValueChanged();
-        }
-    }
-}
diff --git a/src/app/formulaire/elements/select-field.ts b/src/app/formulaire/elements/select-field.ts
index 4818e570918731128fe9a2e13284374b36b1ab83..4b10ec0b7e60b77680252d854a928c5477572f25 100644
--- a/src/app/formulaire/elements/select-field.ts
+++ b/src/app/formulaire/elements/select-field.ts
@@ -16,6 +16,7 @@ import { FormulaireNode } from "./formulaire-node";
 import { FormulaireDefinition } from "../definition/form-definition";
 import { ServiceFactory } from "../../services/service-factory";
 import { FishSpecies } from 'jalhyd/build/verification/fish_species';
+import { sprintf } from 'sprintf-js';
 
 export class SelectField extends Field {
 
@@ -35,6 +36,9 @@ export class SelectField extends Field {
     /** if true, user can select multiple values */
     protected _multiple = false;
 
+    /** soruce identifier for populating with available values */
+    protected source: string;
+
     constructor(parent: FormulaireNode) {
         super(parent);
         this.clearEntries();
@@ -75,30 +79,6 @@ export class SelectField extends Field {
         }
     }
 
-    /**
-     * Reloads available entries, trying to keep the current selected
-     * value; should not notify observers if value did not change
-     */
-    public updateEntries() {
-        // store previous selected entry
-        const pse = this._selectedEntry;
-        this._selectedEntry = undefined;
-        // empty
-        this.clearEntries();
-        // populate
-        this.populate();
-        // keep previously selected entry if possible
-        if (pse) {
-            this.setValue(pse);
-        }
-    }
-
-    /**
-     * Empties then refills entries list with available entries; does
-     * nothing by default (to be overloaded)
-     */
-    protected populate() { }
-
     /**
      * Triggered at the end of parseConfig()
      */
@@ -124,6 +104,7 @@ export class SelectField extends Field {
     }
 
     public notifyValueChanged() {
+        console.log("NOT VAL CHA", this.id, this._selectedEntry)
         this.notifyObservers({
             "action": "select",
             "value": this._selectedEntry
@@ -150,11 +131,20 @@ export class SelectField extends Field {
         if (field["multiple"] !== undefined) {
             this._multiple = field["multiple"];
         }
-        const source = field["source"];
+        this.source = field["source"];
 
+        this.loadEntriesFromSource();
+
+        this.afterParseConfig();
+    }
+
+    /**
+     * Adds available entries to the selector, depending on the "source" identifier
+     */
+    protected loadEntriesFromSource() {
         const nub: Nub = (this.parentForm as FormulaireDefinition).currentNub;
         // ad-hoc cases
-        switch (source) {
+        switch (this.source) {
             // driven by string[], not enum (easier for variable names)
             case "remous_target":
                 this.addEntry(new SelectEntry(this._entriesBaseId + "none", ""));
@@ -211,13 +201,22 @@ export class SelectField extends Field {
                 }
                 break;
 
-            // possible values depend on Session
+            // possible values depend on Session @TODO does not work, because not refreshed when Session gets new Espece nubs
             case "verificateur_species":
+                console.log("[i] loading verif species");
                 // add UIDs of all Espece type Nubs in the session
                 const especeNubs = Session.getInstance().getAllNubs().filter((element) => element.calcType === CalculatorType.Espece);
-                console.log("especeNubs", especeNubs);
                 for (const en of especeNubs) {
-                    this.addEntry(new SelectEntry(en.uid, en.uid, "Espèce personnalisée : " + en.uid));
+                    this.addEntry(
+                        new SelectEntry(
+                            en.uid,
+                            en.uid,
+                            sprintf(
+                                ServiceFactory.instance.i18nService.localizeText("INFO_VERIFICATEUR_CUSTOM_SPECIES"),
+                                ServiceFactory.instance.formulaireService.getFormulaireFromNubId(en.uid).calculatorName
+                            )
+                        )
+                    );
                 }
                 // add all FishSpecies
                 for (let j = 0; j < Object.keys(FishSpecies).length / 2; j++) {
@@ -236,7 +235,6 @@ export class SelectField extends Field {
                     }
                 }
         }
-
-        this.afterParseConfig();
     }
+
 }
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index fb4e4605e9cb9f3e531e22ee2eab7e34d00428f0..88ab30d875391f4710274d3a9271c9f3b1c1fd2e 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -532,6 +532,7 @@
     "INFO_YAXB_TITRE_COURT": "Linear f.",
     "INFO_TRIGO_TITRE": "Trigonometric function",
     "INFO_TRIGO_TITRE_COURT": "Trigo. f.",
+    "INFO_VERIFICATEUR_CUSTOM_SPECIES": "Custom species: %s",
     "INFO_VERIFICATEUR_TITRE": "Fish pass verification",
     "INFO_VERIFICATEUR_TITRE_COURT": "Verification",
     "INFO_ESPECE_TITRE": "Fish species characteristics",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index da9489786236b7f7d42117d08e049d7fc8a7a2e3..97e80ba3f088f098b5d1945ad08ed3f24b0e271a 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -533,6 +533,7 @@
     "INFO_YAXB_TITRE_COURT": "F. affine",
     "INFO_TRIGO_TITRE": "Fonction trigonométrique",
     "INFO_TRIGO_TITRE_COURT": "F. trigo.",
+    "INFO_VERIFICATEUR_CUSTOM_SPECIES": "Espèce personnalisée : %s",
     "INFO_VERIFICATEUR_TITRE": "Vérification d'une passe",
     "INFO_VERIFICATEUR_TITRE_COURT": "Vérification",
     "INFO_ESPECE_TITRE": "Caractéristiques d'une espèce",