diff --git a/ui2/.env b/ui2/.env
deleted file mode 100644
index a20e25f134f48be2a4314477e25635006417b7cf..0000000000000000000000000000000000000000
--- a/ui2/.env
+++ /dev/null
@@ -1,2 +0,0 @@
-VUE_APP_I18N_LOCALE=fr
-VUE_APP_I18N_FALLBACK_LOCALE=en
diff --git a/ui2/src/App.vue b/ui2/src/App.vue
index 5f1fcd5ac86f8dbca8d0e4a3c32344f70d421e58..4a8686e865e2e83f35e06749a390d8e500c54d89 100644
--- a/ui2/src/App.vue
+++ b/ui2/src/App.vue
@@ -19,5 +19,6 @@ export default class App extends Vue {}
   color: $text-default-color;
   display: flex;
   flex-direction: column;
+  height: 100%;
 }
 </style>
diff --git a/ui2/src/components/login/Signin.vue b/ui2/src/components/login/Signin.vue
index 9afed9a4d02df9d41603ae622c5e221103d26198..92da74c8499f132b487e79f365b68f647b068067 100644
--- a/ui2/src/components/login/Signin.vue
+++ b/ui2/src/components/login/Signin.vue
@@ -95,7 +95,7 @@ export default class SignIn extends Vue {
     } catch (error) {
       let message = this.$t("alert.server-error");
       if (error.status === HttpStatusCodes.FORBIDDEN) {
-        message = this.$t("alert.user-uknown");
+        message = this.$t("alert.user-unknown");
       }
       this.alertService.toastError(message, error);
     }
diff --git a/ui2/src/i18n.js b/ui2/src/i18n.js
deleted file mode 100644
index 7841e446501ae5d51b69f9628b2e45d932436ed0..0000000000000000000000000000000000000000
--- a/ui2/src/i18n.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import Vue from "vue";
-import VueI18n from "vue-i18n";
-
-Vue.use(VueI18n);
-
-function loadLocaleMessages() {
-  const locales = require.context(
-    "./locales",
-    true,
-    /[A-Za-z0-9-_,\s]+\.json$/i
-  );
-  const messages = {};
-  locales.keys().forEach((key) => {
-    const matched = key.match(/([A-Za-z0-9-_]+)\./i);
-    if (matched && matched.length > 1) {
-      const locale = matched[1];
-      messages[locale] = locales(key);
-    }
-  });
-  return messages;
-}
-
-export default new VueI18n({
-  locale: process.env.VUE_APP_I18N_LOCALE || "en",
-  fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || "en",
-  messages: loadLocaleMessages(),
-});
diff --git a/ui2/src/locales/en.json b/ui2/src/locales/en.json
new file mode 100644
index 0000000000000000000000000000000000000000..7ee339960ceb596a399a80a6209ea7e5764d0df1
--- /dev/null
+++ b/ui2/src/locales/en.json
@@ -0,0 +1,34 @@
+{
+  "titles": {
+    "login-page": "Welcome to SI-ORE",
+    "applications-page": "My applications",
+    "references-page": "My references"
+  },
+  "login": {
+    "signin": "Sign in",
+    "signup": "Sign up",
+    "login": "Login",
+    "login-placeholder": "Write down the login",
+    "pwd": "Password",
+    "pwd-placeholder": "Write down the password",
+    "pwd-forgotten": "Forgotten password ? "
+  },
+  "validation": {
+    "obligatoire": "Mandatory",
+    "facultatif": "Optional",
+    "invalid-required": "Please fill the field"
+  },
+  "alert": {
+    "cancel": "Cancel",
+    "server-error": "A server error occured",
+    "user-unknown": "Unknown user"
+  },
+  "menu": {
+    "logout": "Log out",
+    "applications": "Applications",
+    "references": "References",
+    "french": "Français",
+    "english": "English",
+    "language": "Language"
+  }
+}
diff --git a/ui2/src/locales/fr.json b/ui2/src/locales/fr.json
index f0f999445a0f227efe0cfdb4d2db34cfb61d8cb0..65bb79fea01ed2eddecae5fa06532b6d61895c1c 100644
--- a/ui2/src/locales/fr.json
+++ b/ui2/src/locales/fr.json
@@ -21,11 +21,14 @@
   "alert": {
     "cancel": "Annuler",
     "server-error": "Une erreur serveur est survenue",
-    "user-uknown": "Identifiants inconnus"
+    "user-unknown": "Identifiants inconnus"
   },
   "menu": {
     "logout": "Se déconnecter",
     "applications": "Applications",
-    "references": "Référentiels"
+    "references": "Référentiels",
+    "french": "Français",
+    "english": "English",
+    "language": "Langue"
   }
 }
diff --git a/ui2/src/main.js b/ui2/src/main.js
index a22b78599bce612d461b9af3de9a4af7b109f7e2..45f5d5e833294d9eb541717d3cc425e231946996 100644
--- a/ui2/src/main.js
+++ b/ui2/src/main.js
@@ -9,6 +9,7 @@ import {
   faExclamationCircle,
   faEye,
   faEyeSlash,
+  faGlobe,
   faPlus,
   faSignOutAlt,
 } from "@fortawesome/free-solid-svg-icons";
@@ -19,19 +20,42 @@ library.add(
   faPlus,
   faExclamationCircle,
   faCheck,
-  faSignOutAlt
+  faSignOutAlt,
+  faGlobe
 );
 Vue.component("vue-fontawesome", FontAwesomeIcon);
 
 import "@/style/global.scss";
 
+// Translation
+import { UserPreferencesService } from "./services/UserPreferencesService";
+import VueI18n from "vue-i18n";
+import i18n_en from "@/locales/en.json";
+import i18n_fr from "@/locales/fr.json";
+
+Vue.use(VueI18n);
+const userPreferencesService = UserPreferencesService.INSTANCE;
+export const i18n = new VueI18n({
+  locale: userPreferencesService.getUserPrefLocale(),
+  messages: {
+    en: i18n_en,
+    fr: i18n_fr,
+  },
+});
+
 // Validation
 import "vee-validate";
-import "@/services/validation/vee-validation-rules";
+import { required } from "vee-validate/dist/rules";
+import { extend } from "vee-validate";
+// Ici on surcharge les messages d'erreur de vee-validate.
+// Pour plus de règles :  https://logaretm.github.io/vee-validate/guide/rules.html
 
-// Translation
-import i18n from "@/i18n";
+extend("required", {
+  ...required,
+  message: i18n.t("validation.invalid-required"),
+});
 
+// Buefy
 Vue.use(Buefy, {
   defaultIconComponent: "vue-fontawesome",
   defaultIconPack: "fas",
diff --git a/ui2/src/services/Fetcher.js b/ui2/src/services/Fetcher.js
index 14117b5bd1ec22ba6868ecc3c3e1b24d0ecf6e6c..36c308f597f15af54a8ce8226f30a576cec7bfd4 100644
--- a/ui2/src/services/Fetcher.js
+++ b/ui2/src/services/Fetcher.js
@@ -1,5 +1,8 @@
 import config from "@/config";
 import { HttpStatusCodes } from "@/utils/HttpUtils";
+import { Locales } from "@/utils/LocaleUtils";
+
+export const LOCAL_STORAGE_LANG = "lang";
 
 export class Fetcher {
   async post(url, data) {
@@ -10,6 +13,9 @@ export class Fetcher {
       mode: "cors",
       credentials: "include",
       body: formData,
+      headers: {
+        "Accept-Language": this.getUserPrefLocale(),
+      },
     });
 
     return this._handleResponse(response);
@@ -22,6 +28,9 @@ export class Fetcher {
       mode: "cors",
       credentials: "include",
       body: formData,
+      headers: {
+        "Accept-Language": this.getUserPrefLocale(),
+      },
     });
 
     return this._handleResponse(response);
@@ -44,6 +53,9 @@ export class Fetcher {
       method: "GET",
       mode: "cors",
       credentials: "include",
+      headers: {
+        "Accept-Language": this.getUserPrefLocale(),
+      },
     });
 
     return this._handleResponse(response);
@@ -56,6 +68,9 @@ export class Fetcher {
       mode: "cors",
       credentials: "include",
       body: formData,
+      headers: {
+        "Accept-Language": this.getUserPrefLocale(),
+      },
     });
 
     if (response.ok) {
@@ -92,4 +107,14 @@ export class Fetcher {
     }
     return formData;
   }
+
+  getUserPrefLocale() {
+    const browserLocale = window.navigator.language.substring(0, 2);
+
+    return (
+      localStorage.getItem(LOCAL_STORAGE_LANG) ||
+      (Object.values(Locales).includes(browserLocale) && browserLocale) ||
+      Locales.FRENCH
+    );
+  }
 }
diff --git a/ui2/src/services/UserPreferencesService.js b/ui2/src/services/UserPreferencesService.js
new file mode 100644
index 0000000000000000000000000000000000000000..ffbe8deca0126f3641d3aeba7037766e9cc0820f
--- /dev/null
+++ b/ui2/src/services/UserPreferencesService.js
@@ -0,0 +1,15 @@
+import app from "@/main";
+import { Fetcher, LOCAL_STORAGE_LANG } from "./Fetcher";
+
+export class UserPreferencesService extends Fetcher {
+  static INSTANCE = new UserPreferencesService();
+
+  constructor() {
+    super();
+  }
+
+  setUserPrefLocale(locale) {
+    localStorage.setItem(LOCAL_STORAGE_LANG, locale);
+    app.$i18n.locale = locale;
+  }
+}
diff --git a/ui2/src/services/validation/vee-validation-rules.js b/ui2/src/services/validation/vee-validation-rules.js
deleted file mode 100644
index 5233349ffd9417038159714e41d71f542dfd0530..0000000000000000000000000000000000000000
--- a/ui2/src/services/validation/vee-validation-rules.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import i18n from "@/i18n";
-import { required } from "vee-validate/dist/rules";
-import { extend } from "vee-validate";
-// See https://logaretm.github.io/vee-validate/guide/rules.html
-// For list of all availables rules
-
-extend("required", {
-  ...required,
-  message: i18n.t("validation.invalid-required"),
-});
diff --git a/ui2/src/style/_common.scss b/ui2/src/style/_common.scss
index f77569bf7d433fdd116661c3895093944a03e251..39ad81f12b509824b271993ad48ff2e54ed5dfcf 100644
--- a/ui2/src/style/_common.scss
+++ b/ui2/src/style/_common.scss
@@ -1,6 +1,13 @@
 // A file for common css across the application
+html,
+body {
+  height: 100%;
+}
+
 .title {
   color: $primary;
+  margin-top: 1.5rem;
+
   &.main-title {
     display: flex;
     align-items: center;
diff --git a/ui2/src/utils/LocaleUtils.js b/ui2/src/utils/LocaleUtils.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ae7fa9b6692bc1738c2fa37687926a8e6e54c14
--- /dev/null
+++ b/ui2/src/utils/LocaleUtils.js
@@ -0,0 +1,4 @@
+export const Locales = {
+  FRENCH: "fr",
+  ENGLISH: "en",
+};
diff --git a/ui2/src/views/common/MenuView.vue b/ui2/src/views/common/MenuView.vue
index a6c9516f43ede007ae285300a69513a5f1be3f36..fb37e23ea6899d9ea4db20ef13e1f4d2032f67d2 100644
--- a/ui2/src/views/common/MenuView.vue
+++ b/ui2/src/views/common/MenuView.vue
@@ -17,34 +17,52 @@
           }}</b-button>
         </div>
       </b-navbar-item>
+      <b-navbar-item tag="div">
+        <b-field>
+          <b-select
+            v-model="chosenLocale"
+            :placeholder="$t('menu.language')"
+            icon="globe"
+            @input="setUserPrefLocale"
+          >
+            <option :value="locales.FRENCH">{{ $t("menu.french") }}</option>
+            <option :value="locales.ENGLISH">{{ $t("menu.english") }}</option>
+          </b-select>
+        </b-field>
+      </b-navbar-item>
     </template>
   </b-navbar>
 </template>
 
 <script>
-import { User } from "@/model/User";
-import { LoginService } from "@/services/LoginService";
 import { Component, Vue } from "vue-property-decorator";
 
+import { LoginService } from "@/services/LoginService";
+import { UserPreferencesService } from "@/services/UserPreferencesService";
+
+import { Locales } from "@/utils/LocaleUtils.js";
+
 @Component({
   components: {},
 })
 export default class MenuView extends Vue {
   loginService = LoginService.INSTANCE;
+  userPreferencesService = UserPreferencesService.INSTANCE;
 
-  loggedUser = new User();
+  locales = Locales;
+  chosenLocale = "";
 
   created() {
-    this.init();
-  }
-
-  async init() {
-    this.loggedUser = await this.loginService.getLoggedUser();
+    this.chosenLocale = this.userPreferencesService.getUserPrefLocale();
   }
 
   logout() {
     this.loginService.logout();
   }
+
+  setUserPrefLocale() {
+    this.userPreferencesService.setUserPrefLocale(this.chosenLocale);
+  }
 }
 </script>
 
diff --git a/ui2/src/views/common/PageView.vue b/ui2/src/views/common/PageView.vue
index d5c5ff80f638cdfc5b3c6b5c10dfa4957f1f6aa2..093f3246daabab85e00925ab45c56c5381c46545 100644
--- a/ui2/src/views/common/PageView.vue
+++ b/ui2/src/views/common/PageView.vue
@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div class="PageView">
     <MenuView v-if="hasMenu" />
     <div class="container PageView-container">
       <slot></slot>
@@ -30,6 +30,10 @@ export default class PageView extends Vue {
 </script>
 
 <style lang="scss" scoped>
+.PageView {
+  height: 100%;
+}
+
 .PageView-container {
   width: 100%;
 }